Размер времени компиляции условных
Я хочу определить макрос, если условие с sizeof
истинно и ничего не делать (но все же компилировать), если оно ложно. Если препроцессор поддерживает sizeof
, он будет выглядеть так:
#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
# define POINTER_FITS_INTO_UINT
#endif
Есть несколько страниц (например, http://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/), которые объясняют, как сделать утверждение времени компиляции на sizeof
(и не скомпилировать, если оно не выполнено), но я не вижу способа расширить этот подход к тому, что я хочу.
Ответы
Ответ 1
Вы просто не можете этого сделать. sizeof - это оператор времени компиляции. #if и #define и связанные с препроцессором. Поскольку препроцессор работает до компилятора, это просто не сработает. Тем не менее, вы можете найти тайный переключатель компилятора, который позволит вам многократно передавать его (т.е. Препроцесс, притворяться компилятором, препроцессом, компилировать), но, честно говоря, я бы отказался от попыток сделать то, что вы хотите. Он не предназначен для работы и, просто, этого не делает.
Лучше всего установить такие параметры, как команды -D, переданные компилятору. Вы можете статически утверждать, что выбранные правильны. Таким образом, вам просто нужно настроить несколько параметров извне для заданного режима компиляции (например, PowerPC Release) и т.д.
Ответ 2
Правильное решение вашей проблемы - использовать стандартные заголовки C99:
#include <stdint.h>
#include <inttypes.h>
Вам нужен только один из двух, потому что #include <inttypes.h>
включает материал из #include <stdint.h>
; однако много материала в <inttypes.h>
относится только к форматированным ввода-выводам с scanf()
и printf()
.
Учитывая предполагаемое условие:
#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
# define POINTER_FITS_INTO_UINT
#endif
То, что вам кажется после, называется:
uintptr_t
Это целочисленный тип без знака, который достаточно велик, чтобы содержать любой указатель (т.е. любой указатель данных в стандарте C; POSIX накладывает дополнительное правило, которое также должно быть достаточно большим, чтобы удерживать указатели на функции). Тип uintptr_t
определяется в <stdint.h>
.
Если впоследствии вы будете печатать такие значения или необработанные указатели, вы можете использовать информацию из <inttypes.h>
:
printf("Pointer = 0x%" PRIXPTR "\n", uintptr_value);
printf("Pointer = 0x%" PRIXPTR "\n", (uintptr_t)any_pointer);
Ответ 3
В этом описывается, как подделывать утверждения времени компиляции в C. Краткая версия заключается в использовании операторов switch:
#define COMPILE_TIME_ASSERT(pred) \
switch(0){case 0:case pred:;}
Если pred
оценивается как 0, как и ложное булевское выражение в C, компилятор будет вызывать ошибку.
Ответ 4
Предполагая C99, вы можете использовать
#include <limits.h>
#include <stdint.h>
#if UINTPTR_MAX <= UINT_MAX
...
что подразумевает sizeof (void *) <= sizeof (intptr_t) <= sizeof (int)
для любой правильной реализации языка C.
Ответ 5
Несмотря на то, что вопрос помечен как C, а не С++, вам может показаться полезным знать, что С++ 0x определяет механизм для статических утверждений, которые проверяются компилятором, а не препроцессором.
Пример Википедии особенно важен:
static_assert (sizeof(int) <= sizeof(T), "T is not big enough!")
Ответ 6
Учитывая, что другие ответы уже объясняли, почему sizeof
нельзя использовать с #if
, позвольте мне предоставить простое решение для вашего случая (на удивление, пока не упомянутое). Взгляни на
https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros.
В нем упоминается несколько предопределенных макросов __SIZEOF_XYZ__
которые фактически могут использоваться на этапе предварительной обработки, то есть также в #if
. Предполагая, что unsigned int
и int
имеют одинаковый размер, ваш пример можно сделать так:
#if __SIZEOF_POINTER__ == __SIZEOF_INT__
#define POINTER_FITS_INTO_UINT
#endif
Ответ 7
Изменить
Не обращайте внимания, как указал Стив Роу, эти значения препроцессора устанавливаются на sizeof
, поэтому мы просто набрали полный круг.
Так как sizeof
не оценивается до момента компиляции, вам нужно полагаться на другие значения препроцессора. Вот как я это сделаю:
#include <values.h>
#if PTRBITS <= INTBITS
# define POINTER_FITS_INTO_UINT
#endif
Ответ 8
Здесь вы вводите в заблуждение два этапа компиляции. Когда вы компилируете программу на C, первым шагом является препроцессор, который разрешает включение, макросы, любую строку, начинающуюся с "#".
Затем идет компиляция, которая случайно оценивает выражения sizeof.
Это два разных бинарных файла, и вы не можете передавать этот тип информации из одного в другой. Вам нужно будет использовать макросы, определенные системой, такие как __i386__
или __x86_64__, если вы хотите определить, на какой архитектуре вы находитесь, а затем выведите размеры int и указателя.
Ответ 9
Один из способов понять это - концепция модели данных (см., например, http://sourceforge.net/p/predef/wiki/DataModels/).
Существует несколько моделей данных, включая LP32 ILP32 LP64 LLP64 ILP64 и на большинстве платформ команда cc frontend определяет текущую модель (например, _ILP32 означает int, long и указатель 32bit, а _LP64 означает long, а указатель - 64 бит).