Подтвердить что ты не робот

"Инициализационный элемент не является постоянным" ошибкой без каких-либо причин в Linux GCC, компилируя C

Я беру файл main.c и компилирую его с помощью gcc -std = c1x -c main.c в Mac OS X, и он отлично работает без ошибок. Затем я делаю то же самое в LinuxMint и на малине Pi, и в обоих случаях он дает мне ошибки о том, что "элемент инициализации не является постоянным".

Один пример проблемной строки с соответствующим кодом:

//STATIC GLOBAL CONSTANTS
const unsigned long long LATITUDE = (long) 3600000;
const unsigned long long LONGITUDE = (long) 1810000;
const unsigned long long MAX_COORDINATES_NUMBER = (LATITUDE-1) + LATITUDE*(LONGITUDE-1); //compiler error: initializer element is not constant

Это должно позволить мне сделать арифметику, не так ли? Я мог бы просто заменить это фактическими числами, и это сработает, но тогда это станет беспорядочным. И все равно отлично работает на моем Mac. Есть ли какой-нибудь вариант в GCC, который я должен указать на Linux (помимо -std = c1x, который вам также не нужен на Mac)?

4b9b3361

Ответ 1

Для языка C требуется инициализатор для статического объекта как константное выражение. (Поскольку инициализация статических объектов происходит до начала main, нет места для любой оценки времени выполнения).

C const ключевое слово не означает "константа", хотя слова, очевидно, связаны между собой. Постоянное выражение - это выражение, которое может быть и в некоторых случаях должно быть оценено во время компиляции. const означает только чтение. Например, в области блока (внутри определения функции) это:

const int r = rand();

является совершенно законным. Очевидно, инициализатор не может быть оценен во время компиляции; const просто означает, что r не может быть изменен после его инициализации.

Когда вы пишете:

const unsigned long long LATITUDE = (long) 3600000;

ссылка на LATITUDE не является константным выражением. Компилятор, конечно, мог бы оценить такую ​​ссылку во время компиляции, но стандарт C не требует этого. (Строка между постоянными и непостоянными выражениями должна была быть проведена где-то, и авторы языка предпочли сделать это различие относительно простым, с небольшим количеством особых случаев.)

Теперь, конечно, верно, что язык C мог быть определен так, что LATITUDE является постоянным выражением. Он находится на С++, и я утверждал, что для C используется аналогичное правило. Но в соответствии с текущими правилами C это не означает, что вы не можете использовать LATITUDE в инициализаторе для статического объекта.

Это также означает, что clang (компилятор, который, как я понимаю, является тем, который вызывается при вводе gcc в MacOS), скорее всего, не соответствует требованиям, поскольку он не может диагностировать эту ошибку. В моей собственной системе Linux я обнаружил, что при вызове с -std=c11 -pedantic gcc 4.7.2 правильно диагностирует ошибку, но clang 3.4 не делает.

За исключением, возможно, этого пункта из раздела 6.6 пункта 10 стандарта ISO C 2011 года (который также существует в стандартах 1990 и 1999 годов):

Реализация может принимать другие формы постоянных выражений.

Можно предположить, что clang принимает LATITUDE как константное выражение, потому что он использует это разрешение, но тогда я все же ожидал бы хотя бы предупреждения от clang -std=c11 -pedantic -Wall -Wextra, и его нет.

UPDATE. Когда я скомпилирую следующее:

#include <stdio.h>

const unsigned long long LATITUDE = (long) 3600000;

int main(void) {
    switch (0) {
        case LATITUDE:
            puts("wrong");
            break;
        default:
            puts("ok(?)");
            break;
    }
}

с clang 3.0 с параметрами -std=c99 -pedantic, я получаю:

c.c:7:14: warning: expression is not integer constant expression (but is allowed as an extension) [-pedantic]
        case LATITUDE:
             ^~~~~~~~
1 warning generated.

С clang 3.4, предупреждение:

c.c:7:14: warning: expression is not an integer constant expression; folding it to a constant is a GNU extension [-Wgnu-folding-constant]
        case LATITUDE:
             ^~~~~~~~
1 warning generated.

Таким образом, clang признает, что это не постоянное выражение; ошибка в том, что она не предупреждает об объявлении MAX_COORDINATES_NUMBER.