Условная компиляция и оценка времени компиляции выражений в ANSI C

Я хотел бы сделать следующее, но компилятору это не нравится:

unsigned short foo = 1;
// do something with foo
#if sizeof(short) * CHAR_BIT > 16
   foo &= 0xffff;
#endif

Я знаю, что это выражение всегда можно полностью оценить во время компиляции, но, может быть, оно оценивается только после того, как препроцессор сделает свое дело? Возможно ли это в ANSI C или мне просто нужно выполнить проверку во время выполнения?


person Robert S. Barnes    schedule 26.07.2011    source источник
comment
Не существует стандартного способа запросить размер типа данных через препроцессор. Но, возможно, вас больше интересует количество значащих бит вашего типа данных? Тогда вам вообще не следует использовать short, а следуйте совету @larsmans и используйте соответствующий тип данных. Действительно правильным было бы int_least16_t для типа, который имеет по крайней мере 16 значащих битов.   -  person Jens Gustedt    schedule 26.07.2011


Ответы (2)


Вы не можете использовать sizeof в выражении препроцессора. Вместо этого вы можете сделать что-то вроде этого:

#include <limits.h>

#if SHRT_MAX > 32767
    /* do soemthing */
#endif
person Paul R    schedule 26.07.2011
comment
+1, хотя это не совсем правильно, поскольку ОП запрашивал размер типа данных, а не его ширину. Теоретически short может иметь много дополнительных битов. Тогда исходное выражение сработает, а ваше выражение — нет. - person Jens Gustedt; 26.07.2011
comment
@larsmans: Не могу этого сделать, это ANSI C. int16_t, а все остальные типы ширины являются частью C99. - person Robert S. Barnes; 26.07.2011
comment
@Jens Gustedt: Разрешает ли стандарт ANSI C заполнять биты? Что меня действительно интересует, так это то, сколько битов точности дает мне шорт. Мне нужно работать ровно с 16 битами. Поэтому я думаю, что приведенная выше идея будет работать нормально, хотя вместо этого я бы использовал USHRT_MAX. - person Robert S. Barnes; 26.07.2011
comment
@Роберт. Под ANSI C я полагаю, вы имеете в виду C89? AFAIR C89 был даже менее строгим, чем C99, поэтому он окончательно допускает заполнение битов. Если вам действительно нужен C89, вы должны как-то проверить существование типов int16, #ifdef INT16_MAX может это сделать. Если он не существует, используйте приближение через [U]SHORT_MAX. Осторожно, на странных платформах unsigned short просто маскируйте бит знака short. Но на большинстве платформ в настоящее время должно быть inttypes.h, лучше используйте его, если можете. - person Jens Gustedt; 26.07.2011

Если ваша цель состоит в том, чтобы остановить компиляцию, когда тип данных имеет неправильный размер, полезен следующий метод:

struct _check_type_sizes
{
  int int_is_4_bytes[(sizeof(int) == 4) ? 1 : -1];
  int short_is_2_bytes[(sizeof(short) == 2) ? 1 : -1];
};

(Здесь функция sizeof() интерпретируется компилятором, а не препроцессором.)

Основным недостатком этого метода является то, что ошибка компилятора не очень очевидна. Убедитесь, что вы написали очень четкий комментарий.

person Ian Goldby    schedule 26.07.2011
comment
+1 за творчество. Будет ли это работать с выражением sizeof(short) * CHAR_BIT > 16 ? Тот факт, что short составляет 2 байта, не означает, что это 16 бит. ANSI C гарантирует только то, что байты составляют не менее 8 бит, но они могут быть и больше. Например, есть архитектуры с 9-битными байтами. - person Robert S. Barnes; 26.07.2011