Избегать представления ловушки с memcpy

Обратите внимание на следующий код:

float float_value = x; // x is any valid float value
int int_value = 0;
size_t size = sizeof(int) < sizeof(float) ? sizeof(int) : sizeof(float);
memcpy(&int_value, &float_value, size);

Насколько я знаю, это может привести к представлению ловушки. Мои вопросы:

  • Это правда?
  • Если нет, почему?
  • Если нет, существует ли другой способ избежать возможного представления ловушки?

Ответ 1

Санкционированный способ, который не создает никакого ловушечного представления,

unsigned char obj[sizeof float];
memcpy(obj, &float_value, sizeof float);

Затем вы можете использовать байты представления объекта для создания желаемого int.

Но использование целых чисел фиксированной ширины, как упомянуто Stephen Canon, лучше - если у вас нет странного размера float.

Ответ 2

Вам не нужно memcpy, если вы хотите только проверить значения там. Самый простой способ - просто бросить

unsigned char const* p = &float_object;

Указатель, передаваемый всем типам char, всегда гарантирует что-то действительное, с помощью которого вы можете выполнить простую арифметику. Вы в безопасности до тех пор, пока выполняете разыменование в границах, заданных sizeof float_object.

Если вы хотите рассматривать это как число, самым безопасным является выбор целого числа без знака фиксированной ширины, наиболее вероятно uint32_t. Если вы знаете, что требования к ширине выполнены, это должно дать вам все, что вам нужно.

Как уже упоминалось, это работает хорошо, пока вы не пишете этот указатель. Тогда правила псевдонимов указателей могут привести к тому, что оптимизатор пойдет не так.

Ответ 3

Да, это может привести к представлению ловушки. Что касается того, как этого избежать:

  • Утвердить, что sizeof(int32_t) == sizeof(float)
  • Используйте int32_t вместо int.

Целые числа с фиксированной шириной могут не допускать ловушки. В частности, стандарт требует, чтобы у них не было битов дополнения, и вы не можете иметь представление ловушки без заполнения.