Макросы A
и B
немного отвлекают. Это:
#define A 5
#define B 3
int difference = A - B;
в точности соответствует этому:
int difference = 5 - 3;
так что давайте обсудим последнее.
5 - 3
является константным выражением , которое является выражением, которое «может быть оценено во время перевода, а не во время выполнения, и, соответственно, может использоваться в любом месте, где может быть константа». Это также * целочисленное константное выражение ". Например, метка case должна быть целочисленным константным выражением, поэтому вы можете написать либо:
switch (foo) {
case 2: /* this is a constant */
...
}
или это:
switch (foo) {
case 5 - 3: /* this is a constant expression */
...
}
Но обратите внимание, что в определении сказано, что может быть оценено во время перевода, а не то, что оно должно быть. Есть некоторые контексты, которые требуют константных выражений, и в этих контекстах выражение должно быть вычислено во время компиляции.
Но если предположить, что difference
объявлено внутри некоторой функции, инициализатор не является одним из этих контекстов.
Любой компилятор стоит того, за что вы платите (даже если он бесплатный), уменьшит 5 - 3
до 2
во время компиляции и сгенерирует код, который хранит значение 2
в difference
. Но это не обязательно. Стандарт C определяет поведение программ; это не определяет, как это поведение должно быть реализовано. Но можно предположить, что любой используемый компилятор заменит 5 - 3
на 2
.
Даже если вы напишите:
int difference = 2;
компилятор может легально генерировать код, который загружает значение 5
в регистр, вычитает из него 3
и сохраняет содержимое регистра в difference
. Это было бы глупо, но языковой стандарт не исключает этого.
Пока окончательный результат состоит в том, что difference
имеет значение 2
, языковой стандарт не заботится о том, как это делается.
С другой стороны, если вы напишите:
switch (foo) {
case 5 - 3: /* ... */
case 2: /* ... */
}
затем компилятор должен вычислить результат, чтобы он мог диагностировать ошибку (у вас не может быть двух меток с одинаковым значением.
Наконец, если вы определяете difference
в области видимости файла (вне какой-либо функции), тогда начальное значение делает должно быть постоянным. Но реальное различие в этом случае не в том, будет ли 5 - 3
вычисляться во время компиляции, а в том, разрешено ли использовать непостоянное выражение.
Ссылка: последний вариант стандарта C 2011 года: N1570 (большой PDF); константные выражения обсуждаются в разделе 6.6.