Ошибка «элемент инициализатора не является константой» при попытке инициализировать переменную с помощью const - PullRequest
169 голосов
/ 11 июня 2010

Я получаю сообщение об ошибке в строке 6 (инициализация my_foo для foo_init) следующей программы, и я не уверен, что понимаю, почему.

typedef struct foo_t {
    int a, b, c;
} foo_t;

const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;

int main()
{
    return 0;
}

Имейте в виду, что это упрощенная версия большегомногофайловый проект, над которым я работаю.Цель состояла в том, чтобы в объектном файле была одна константа, которую несколько файлов могли бы использовать для инициализации структуры состояний.Так как это встроенная цель с ограниченными ресурсами и структура не такая маленькая, я не хочу иметь несколько копий исходного кода.Я предпочел бы не использовать:

#define foo_init { 1, 2, 3 }

Я также пытаюсь написать переносимый код, поэтому мне нужно решение, которое действительно C89 или C99.

Это связано сORG в объектном файле?Инициализированные переменные входят в один ORG и инициализируются путем копирования содержимого второго ORG?

Может быть, мне просто нужно изменить свою тактику, и чтобы при запуске функция инициализации выполняла все копии.Разве есть другие идеи?

Ответы [ 4 ]

242 голосов
/ 11 июня 2010

В языке C объекты со статической продолжительностью хранения должны быть инициализированы с константными выражениями или с агрегатными инициализаторами, содержащими константные выражения.

«Большой» объект никогда не является константным выражением в C, даже если объект объявлен как const.

Более того, в языке C термин «константа» относится к буквальным константам (например, 1, 'a', 0xFF и т. Д.), Элементам перечисления и результатам таких операторов, как sizeof. Константные объекты (любого типа) не являются константами в терминологии языка C. Их нельзя использовать в инициализаторах объектов со статической продолжительностью хранения независимо от их типа.

Например, это НЕ константа

const int N = 5; /* `N` is not a constant in C */

Вышеуказанное N будет константой в C ++, но не является константой в C. Итак, если вы попытаетесь сделать

static int j = N; /* ERROR */

вы получите ту же ошибку: попытка инициализировать статический объект с непостоянной величиной.

Это причина того, что в языке C мы преимущественно используем #define для объявления именованных констант, а также прибегаем к #define для создания именованных агрегатных инициализаторов.

72 голосов
/ 11 июня 2010

Это ограничение языка.В разделе 6.7.8 / 4:

Все выражения в инициализаторе для объекта со статической продолжительностью хранения должны быть константными выражениями или строковыми литералами.

В разделе6.6 спецификация определяет то, что должно считаться константным выражением.Нет, где говорится, что константная переменная должна рассматриваться как константное выражение.Это допустимо для компилятора, чтобы расширить это (6.6/10 - An implementation may accept other forms of constant expressions), но это ограничит переносимость.

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

int main()
{
    foo_t my_foo = foo_init;
    return 0;
}
5 голосов
/ 27 ноября 2015

Только для сравнения и сравнения Код от http://www.geeksforgeeks.org/g-fact-80/ / Код не выполняется в gcc и передается в g ++ /

#include<stdio.h>
int initializer(void)
{
    return 50;
}

int main()
{
    int j;
    for (j=0;j<10;j++)
    {
        static int i = initializer();
        /*The variable i is only initialized to one*/
        printf(" value of i = %d ", i);
        i++;
    }
    return 0;
}
2 голосов
/ 10 декабря 2015

Это немного устарело, но я столкнулся с подобной проблемой. Вы можете сделать это, если используете указатель:

#include <stdio.h>
typedef struct foo_t  {
    int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
    const foo_t *const f1 = &s_FooInit;
    const foo_t *const f2 = s_pFooInit;
    printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
    printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...