Ошибка "элемент инициализации не является константой" при попытке инициализировать переменную с константой
Я получаю сообщение об ошибке в строке 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?
Возможно, мне просто нужно будет изменить свою тактику, а функция инициализации сделает все копии при запуске. Разве есть другие идеи?
Ответы
Ответ 1
В языках C объекты со статическим временем хранения должны быть инициализированы с помощью константных выражений или с помощью агрегатных инициализаторов, содержащих постоянные выражения.
"Большой" объект никогда не является постоянным выражением в C, даже если объект объявлен как const
.
Более того, в языке C термин "константа" относится к литеральным константам (например, 1
, 'a'
, 0xFF
и т.д.), Перечисляемым членам и результатам таких операторов, как sizeof
. Объекты Const-certified (любого типа) не являются константами в терминологии языка C. Они не могут использоваться в инициализаторах объектов со статической продолжительностью хранения, независимо от их типа.
Например, это НЕ постоянное
const int N = 5; /* 'N' is not a constant in C */
Вышеуказанное N
будет константой в C++, но оно не является константой в C. Итак, если вы попытаетесь сделать
static int j = N; /* ERROR */
вы получите ту же ошибку: попытка инициализировать статический объект с непостоянной.
Вот почему на языке C мы преимущественно используем #define
для объявления именованных констант, а также прибегаем к #define
для создания именованных агрегатных инициализаторов.
Ответ 2
Это ограничение языка. В разделе 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;
}
Ответ 3
Просто для иллюстрации с помощью сравнения и контрастности. Код находится с 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;
}
Ответ 4
Это немного устарело, но я столкнулся с подобной проблемой. Вы можете сделать это, если используете указатель:
#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;
}