Есть ли способ ввести каламбур, который действителен как в C, так и в C++? Предпочтительно низкие накладные расходы и избегание тривиальных взломов препроцессора.
В C89 я знаю, что могу сделать что-то вроде этого:
unsigned int float_bits(float num) {
return *(unsigned int *)#
}
Однако это нарушает строгое правило алиасинга C99. Так что что-то вроде этого может быть более переносимым для различных стандартов C:
unsigned int float_bits(float num) {
union { float f; unsigned int i; } u;
u.f = num;
return u.i;
}
Но я знаю, что это недопустимый C++, потому что только один член объединения может быть «активным» в каждый момент времени. Типичное решение для C и C++ выглядит примерно так:
unsigned int float_bits(float num) {
unsigned int i;
memcpy(&i, &num, sizeof(int));
return i;
}
Однако это зависит от того, сможет ли компилятор оптимизировать вызов memcpy. Является ли memcpy единственным методом, переносимым между стандартами C и C++?
(unsigned int *)&num
не надежен. - person chux - Reinstate Monica   schedule 02.11.2019memcpy
это путь сюда. Или просто не занимайтесь каламбуром, он редко нужен :) - person DeiDei   schedule 02.11.2019memcpy
— единственный способ, мы можем использовать этот вопрос в качестве канонического дубликата для всех будущих вопросов этого типа. - person Richard Critten   schedule 02.11.2019memcpy
более (или менее) надежен, чем(unsigned int *)&num
? (Оба потерпят неудачу, еслиsizeof(float) != sizeof(int)
.) - person Adrian Mole   schedule 02.11.2019sizeof(float) == sizeof(int)
, то*(unsigned int *)#
является UB.memcpy
допустим в этом случае, аstatic_assert
можно использовать для проверки соответствия размеров. - person Richard Critten   schedule 02.11.2019* (unsigned int *) &num
нарушило бы правило C об использовании псевдонимов: компилятор имеет право предположить, что доступ черезunsigned int *
не дает доступа к объекту, который был определен какfloat
, независимо от приведений. При оптимизации такой код, какnum = 4; * (unsigned int *) &num = 0; printf("%d\n", num); printf("%d\n", num);
, может печатать, среди прочего, «4» и «0», или «4» и «4», или «0» и «0». - person Eric Postpischil   schedule 02.11.2019unsigned char*
, но как извлечь из него какой-либо другой тип значения? Похоже, вы просто в конечном итоге реализуетеmemcpy
самостоятельно. - person Davis Herring   schedule 03.11.2019char *
- person dbush   schedule 03.11.2019T
, всегда равенT
независимо от memcpying. - person M.M   schedule 04.11.2019