Избегать представления ловушки с 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
.
Целые числа с фиксированной шириной могут не допускать ловушки. В частности, стандарт требует, чтобы у них не было битов дополнения, и вы не можете иметь представление ловушки без заполнения.