Пример чего-то, что есть и не является «константным выражением» в C? - PullRequest
8 голосов
/ 21 сентября 2010

Я немного запутался между тем, что является и не является константным выражением в C, даже после долгих поисков Google.Не могли бы вы привести пример чего-то, что является, а что нет, выражением константы в C?

Ответы [ 6 ]

15 голосов
/ 21 сентября 2010

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

Например, (24*60*60) может быть вычислено обоими, но sizeof struct foo известно только компилятору. Это различие может иметь значение, если вы пытаетесь проверить, что struct определено для соответствия внешнему обязательному размеру или что его элементы сопоставлены с внешне заданными смещениями. (Этот вариант использования часто возникает при кодировании драйверов устройств, где struct описывает регистры устройства как расположенные в пространстве памяти.)

В этом случае вы не можете просто сказать #if (sizeof(struct UART) == 12), потому что препроцессор работает на шаг впереди компиляции и просто не может знать размер каких-либо типов. Это, однако, константное выражение и будет допустимым в качестве инициализатора для глобальной переменной (например, int UARTwords = sizeof(struct UART) / sizeof(short);) или для объявления размера массива (например, unsigned char UARTmirror[sizeof(struct UART)];)

13 голосов
/ 21 сентября 2010

Постоянное выражение может быть оценено во время компиляции. Это означает, что в нем нет переменных. Например:

5 + 7 / 3

- это константное выражение. Что-то вроде:

5 + someNumber / 3

нет, если someNumber является переменной (т. Е. Не является постоянной времени компиляции).

4 голосов
/ 21 сентября 2010

Никто, кажется, не упомянул еще один вид константного выражения: адресные константы.Адрес объекта со статической продолжительностью хранения является адресной константой, поэтому вы можете делать такие вещи в области видимости файла:

char x;
char *p = &x;

Строковые литералы определяют массивы со статической продолжительностью хранения, поэтому это правило также объясняет, почемуВы можете сделать это в области действия файла:

char *s = "foobar";
3 голосов
/ 21 сентября 2010

Любой однозначный литерал является константным выражением.

3     0.0f    '\n'

(Строковые литералы странные, потому что они на самом деле массивы. Кажется, "hello" на самом деле не является константой, так как в конечном итоге приходится связывать и все такое, а адрес и содержимое могут меняться во время выполнения.)

Большинство операторов (sizeof, приведений и т. Д.), Применяемых к константам или типам, являются константными выражениями.

sizeof(char)
(byte) 15

Любое выражение, включающее только константные выражения, само по себе также является константным выражением.

15 + 3
0.0f + 0.0f
sizeof(char)

Любое выражение, включающее вызовы функций или неконстантные выражения, обычно не константное выражение.

strlen("hello")
fifteen + x

Статус любого макроса как константного выражения зависит от того, к чему он расширяется.

/* Always a constant */
#define FIFTEEN 15

/* Only constant if (x) is
#define htons(x)  (( ((x) >> 8) | ((x) << 8) ) & 0xffff) 

/* Never constant */
#define X_LENGTH  strlen(x)

Изначально у меня было кое-что о const идентификаторах, но я проверил это и, очевидно, это не относится к C. const, как ни странно, не объявляет константы (по крайней мере, не те) константы "достаточно для использования в switch выражениях). В C ++, однако, это так.

2 голосов
/ 21 сентября 2010

Также integral character constants как 'a' или '\n' являются константами, которые компилятор распознает как таковые. Они имеют тип int.

2 голосов
/ 21 сентября 2010

Еще одна забавная маленькая морщинка: в C значение enum является константой, но ее можно использовать только после завершения объявления enum. Следующее, например, недопустимо в стандарте C, хотя это допустимо в C ++:

enum {foo=19, bar, boz=bar+5;};

Можно переписать:

enum {foo=19, bar}; enum {boz=bar+5;};

хотя в итоге будет определено несколько различных типов перечисления, а не тот, который содержит все значения.

...