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

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

Ответы на вопрос(6)

Решение Вопроса

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

5 + 7 / 3

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

5 + someNumber / 3

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

 caf21 сент. 2010 г., 03:53
адрес хотя некоторые переменные могут быть в постоянном выражении (те, которые имеют статическую длительность хранения).
 Dave Gallagher20 сент. 2010 г., 23:22
Большое спасибо Карл, очень полезно! :)

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

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 ++, однако, это так.

 pmg21 сент. 2010 г., 00:16
Да @cHao ...C а такжеC++ есть свои отличия. ВC, вашzero выше - это, прежде всего, объект. Вы можете взять его адрес, подать заявкуsizeof к этому ... (не знаю, сможете ли вы сделать это вC++)
 RBerteig21 сент. 2010 г., 01:19
@pmg, многие регистры устройств ввода / вывода объявлены правильноconst volatile,const указывает на регистр только для чтения.volatile указывает регистр, значение которого может изменяться вне потока управления этого модуля компиляции, и регистр состояния оборудования является отличным примером такого значения. Вся хитрость заключается в том, чтобы получить объявление регистра, который будет определен (и связан), чтобы он, разумеется, был размещен на реальном устройстве ввода-вывода.
 Clifford21 сент. 2010 г., 18:40
@pmg: Хороший вопрос.
 cHao21 сент. 2010 г., 00:34
@pmg: Кажется, так. В C ++zero действует как реальная переменная и константное выражение. Я могу взять адрес этого, подать заявкуsizeof, все, кроме изменения его значения. Даже это может быть сделано до некоторой степени, но я бы не рассчитывал на то, что не все испортит. (Компилятор, вероятно, жестко закодирован 0 вместоzero везде, где это нужно константе.)
 pmg21 сент. 2010 г., 01:28
Я имею в виду: естьfixed как вconst volatile int fixed = 42; a C++ например, константа, используемая в качестве метки регистра в операторе switch? (У меня здесь нет компилятора C ++, или я бы его протестировал ... и мне не хочется искать спецификацию C ++ и просматривать ее)
 pmg20 сент. 2010 г., 23:46
@Clifford: вC99, sizeof, примененный к VLA, не определяет константу "6.5.3.4 ... Если тип операнда является типом массива переменной длины, операнд вычисляется; в противном случае операнд не оценивается, а результат является целочисленной константой. «.
 pmg21 сент. 2010 г., 00:50
Как насчетconst volatile int fixed = 42;? :)
 Jens Gustedt21 сент. 2010 г., 00:03
Хм, я немного сомневаюсь, что строковые литералы являются константными выражениями. У них есть типchar[], вы можете взять их адрес и применить[] оператор для них, например"Hello"[1] является допустимым выражением.
 pmg20 сент. 2010 г., 23:58
@cHao:const является классификатором типа. Это относится к объектам ... и ни один объект не может быть константой.
 cHao21 сент. 2010 г., 00:13
@pmg: если вы скажетеconst int zero = 0, затемswitch (x) { case zero: break; default: break; } компилируется в C ++. Это все еще не действительный C, хотя.
 Clifford20 сент. 2010 г., 23:35
Обратите внимание, что sizeof ()всегда константное выражение, даже если аргумент является неконстантным выражением, так как этотип на выражение, которое является аргументом, а не само выражение.
 cHao21 сент. 2010 г., 19:00
volatile const На самом деле они не являются константами - они просто переменные только для чтения. Так что нет, они не будут рассматриваться как постоянные. я точно уверенextern В вещах тоже есть некоторые странные правила, особенно если они не объявлены и не установлены одновременно.

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

char x;
char *p = &x;

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

char *s = "foobar";
 abhiarora18 мар. 2017 г., 21:42
Вот что я искал!
 R..21 сент. 2010 г., 03:17
+1, но следует отметить, что такого рода константное выражение обычноне фактическая константа во время компиляции, и, возможно, не во время компоновки, если вы используете динамическое связывание. В большинстве реальных реализаций это приводит кперемещение.

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

Например(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)];)

 Tim15 авг. 2017 г., 18:39
@Carl: Приятно знать, спасибо. Определены ли «ограниченные константные выражения» в какой-либо ссылке? Я не нахожу это в стандарте C11.
 Carl Norum21 сент. 2010 г., 00:07
+1, те, которые препроцессор не может обработать, называются «ограниченные константные выражения», я считаю.
 Carl Norum17 авг. 2017 г., 21:53
Привет @ Тим, у меня нет под рукой спецификации, но у Microsoft есть кое-что здесь:docs.microsoft.com/en-ca/cpp/c-language/c-constant-expressions

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

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

Это может быть переписано:

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

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

 Jens Gustedt21 сент. 2010 г., 00:06
Просто упомянуть, что этиenum константы имеют типint.

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

Ваш ответ на вопрос