«Элемент инициализатора не является константой» при определении объекта как члена функции stati c - PullRequest
3 голосов
/ 12 февраля 2020

Следующий код компилируется без жалоб:

struct s {
    const int a;
};

static const struct s *s = &(const struct s) {
    .a = 5
};

int main(void) {
    (void) s;
    return 0;
}

Однако, если мы переместим определение s в тело main, то есть:

struct s {
    const int a;
};

int main(void) {
    static const struct s *s = &(const struct s) {
        .a = 5
    };
    (void) s;
    return 0;
}

мы получите ошибку:

error: initializer element is not constant
    static const struct s* s = &(const struct s) {
                               ^

Поскольку в обоих случаях мы имеем дело с инициализацией stati c (т.е. во время компиляции), почему второй вариант использования является недопустимым? Есть ли способ сделать его легальным в контексте функции?

(я проверил это с помощью G CC 7.3.0 и clang 6.0.0, и они оба сообщают об этом как об ошибке)

1 Ответ

4 голосов
/ 12 февраля 2020

Per C 2018 6.6 («Выражения констант») 7:

Для константных выражений в инициализаторах допускается больше широты. Такое постоянное выражение должно быть или оценивать одно из следующего:… адресную константу или…

В течение 6,6 9:

Адресная константа представляет собой нулевой указатель, указатель на l-значение, обозначающее объект хранения * stati c, или указатель на обозначение функции…

Затем в 6.5.2.5 («Составные литералы») 5, мы имеем:

… Если составной литерал находится вне тела функции, объект имеет длительность хранения c; в противном случае он имеет автоматическую c продолжительность хранения, связанную с вмещающим блоком.

Таким образом, в первом случае составной литерал является объектом со статикой c длительности хранения и указателем на это адресная константа. Во втором случае составной литерал является объектом с автоматическим c сроком хранения, и указатель на него не является адресной константой.

...