2016-01-30 6 views
1

Я ищу способ #define макроса, который принудительно применяет его аргументы для компиляции констант времени и в то же время может использоваться в выражении. Этот метод должен работать под управлением C90 и быть совместимым с повышением, если возможно, также переносимым для разных вариантов C++. Также предпочтительнее использовать 0-footprint для памяти.Макрос для использования в выражении при применении своих аргументов для компиляции констант времени

В качестве примера рассмотрим макрос минимального времени компиляции. Поведение должно быть:

#define CT_MIN(CTC_A, CTC B) <<<MAGIC>>> 

int a = 1; 
int b = a + CT_MIN(1,4); /* OK */ 
int c = a + CT_MIN(a,4); /* COMPILER DIAGNOSTIC */ 

Чтобы спровоцировать декомпилировать диагностики, в общем, я мог бы эмулировать с статических проверок что-то вроде:

typedef char ct_check_is_ct_constant[(CTC_A != 0) + 1]; 

, который не компилируется (или поднимет некоторые диагностические по крайней мере,), если для CTC_A используется что-либо, кроме постоянной времени (времени) компиляции; но если CTC_A является числом, он всегда будет успешным (с некоторой осторожностью с областями). Но это утверждение будет работать только в макрокоманде с несколькими утверждениями и поэтому не может быть использовано как часть выражения.

Я предположил бы, что-то в строках:

#define CT_MIN(CTC_A, CTC_B)     \ 
     (<expr check CTC_A>,     \ 
      <expr check CTC_B>,     \ 
      (CTC_A) < (CTC_B))? (CTC_A) : (CTC_B) \ 
     ) 

Но я понятия не имею, как выражения должны выглядеть, и если такая вещь существует.

Любые идеи?

фона:

У меня есть огромное количество констант из не слишком много надежных источников через costumized заголовка. Эти константы сильно параметризуют мой код. Я хочу реализовать проверку нулевого следа во время препроцессора и время компиляции для этих констант, чтобы проверить как мои предположения, среду, так и мои навыки, чтобы написать правильный генератор кода.

+0

Берегись типами VLA. Я думаю, вы могли бы определить тип структуры с битовым полем, размер которого определен в терминах аргумента макроса, хотя я бы не стал доверять себе, чтобы знать обо всех предостережениях и получить его полностью прав. – user2357112

+0

@ user2357112 :-) Я не совсем уверен, как типы VLA могут использоваться для достижения макроса MIN, который не будет работать во время компиляции, если его аргументы не являются константами времени компиляции. –

+0

Я говорю, чтобы убедиться, что вы случайно не объявляете тип VLA, думая, что длины массива всегда являются константой времени компиляции. – user2357112

ответ

2

Вы можете использовать sizeof применительно к анонимной структуры с одним полем, тип которого является локально определенные enum, значения которого должны быть постоянные целые выражения:

#define CT_MIN(CTC_A, CTC_B)            \ 
    (sizeof(struct { enum { must_be_constant_expression = CTC_A } x; }), \ 
     sizeof(struct { enum { must_be_constant_expression = CTC_B } x; }), \ 
     (CTC_A) < (CTC_B) ? (CTC_A) : (CTC_B)        ) 

Сообщения об ошибках, полученные лязгом очень четко:

enumassert.c:32:24: error: expression is not an integer constant expression 
    int c = a + CT_MIN(a,4); /* COMPILER DIAGNOSTIC */ 
        ^
enumassert.c:17:60: note: expanded from macro 'CT_MIN' 
    (sizeof(struct { enum { must_be_constant_expression = CTC_A } x; }), \ 
                 ^

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

#define CT_MIN(CTC_A, CTC_B)            \ 
    (sizeof(struct { enum { must_be_constant_expression = (int)(CTC_A) } x; }), \ 
     sizeof(struct { enum { must_be_constant_expression = (int)(CTC_B) } x; }), \ 
     (CTC_A) < (CTC_B) ? (CTC_A) : (CTC_B)        ) 
+0

выглядит хорошо. Этот подход добавляет что-то в пространство имен, в котором используется макрос? –

+0

Также как насчет констант с плавающей точкой - будет что-то вроде: sizeof (struct {enum {XXX = (int) (CTC_A)} x;}) 'трюк? Кроме того, переполнение может вызвать проблемы, не так ли? Будет ли неподписанный актерский состав (unsigned int) хорошо определен на больших поплавках? –

+0

@MarkA .: Я не думаю, что он даже добавляет символ 'must_be_constant_expression' в пространство имен, потому что он ограничен внутри' struct' и переопределяется чуть ниже с другим значением без предупреждения. – chqrlie

1

Для оценки как с плавающей точкой и целым во время компиляции константы I думаю, я могу использовать решение @ chqrlie и немного его обновить.

Выражение для проверки, если параметр компиляции постоянная времени может быть:

sizeof(struct { enum { must_be_constant_expression = (int) (!(CTC_A))} x; }) 

(! Я не уверен, что если унарный дает выход в int или что-то типа CTC_A)

Это должно обрабатывать большую часть всего, что операция MIN может быть разумно выполнена во время компиляции.затем

Полные макросъемки:

#define CT_MIN(CTC_A, CTC_B)               \ 
    (sizeof(struct { enum { must_be_constant_expression = (int) (!(CTC_A)) } x; }), \ 
     sizeof(struct { enum { must_be_constant_expression = (int) (!(CTC_B)) } x; }), \ 
     (CTC_A) < (CTC_B) ? (CTC_A) : (CTC_B)           \ 
    ) 
+0

'! 'оператор действительно оценивает значение' int' со значением '0' или' 1'. Это решение должно работать так же, как и простое приложение, поскольку по какой-то причине «clang» жалуется, что он не является константой времени компилятора, если аргумент является двойным, утверждая, что его сведение к константе является расширением GNU. Я не понимаю, почему, но это делает это решение непригодным. – chqrlie

+0

@chqrlie Смотрите мой комментарий к вашему обновленному ответу. ... Является ли это ошибкой компилятора? Я не являюсь причиной в стандарте ... –

+0

Хорошо. Найдено причина в стандарте: ANSI/ISO 9899: 1990 6.5.2.2 Спецификации перечисления: «Ограничения: [...] константа перечисления должна быть интегральным постоянным выражением [...]» и 6.4. Константные выражения: «[. ..] Интегральное постоянное выражение [...] должно содержать только операнды, которые являются [... stuff ...] sizeof выражениями и плавающими константами, которые являются непосредственными операндами приведений. [...] " –