Инициализация Const Struct с другими экземплярами Const Struct - PullRequest
9 голосов
/ 12 сентября 2011

Мне любопытно, почему следующий фрагмент кода не компилируется:

typedef struct Foo {
    int a;
    int b;
} Foo;

static const Foo FooZero = { 0, 0 };

typedef struct Bar {
    Foo foo;
    int c;
} Bar;

static const Bar BarZero = { FooZero, 0 };

Он жалуется на использование FooZero, заявляя, что FooZero не Compile-Time Constant

Но не так ли? Что я здесь не понимаю?

Очевидно, я могу просто заменить использование FooZero в инициализаторе на { 0, 0 } - моя цель при задании вопроса не в том, как обойти проблему - я пытаюсь понять причину, по которой FooZero на самом деле не является константой времени компиляции.

Спасибо

Ответы [ 2 ]

10 голосов
/ 12 сентября 2011

В основном это связано с инициализацией.

Инициализированные переменные обычно инициализируются не кодом, который говорит «поместите это значение в это место», а определением, которое загружает определенный диапазон значений, .data соответственно. .rodata сегмент, к месту памяти, где он должен быть. Это делается загрузчиком файлов ОС. (Строго говоря, это не свойство C, которое ничего об этом не знает, а среда исполнения.)

Тем не менее, невозможно сказать, чтобы часть этой области памяти была скопирована из другой. Но было бы возможно, чтобы сам компилятор распознал цель объявления и поместил те же значения в разные места. Но это, вероятно, было бы слишком много "догадок".

В вашем случае: разве указатель на FooZero не может быть лучшим решением? Значения одинаковы ...

typedef struct Foo {
    int a;
    int b;
} Foo;

static const Foo FooZero = { 0, 0 };

typedef struct Bar {
    Foo * foo;
    int c;
} Bar;

static const Bar BarZero = { &FooZero, 0 };

Или наоборот:

typedef struct Foo {
    int a;
    int b;
} Foo;

typedef struct Bar {
    Foo foo;
    int c;
} Bar;

static const Bar BarZero = { { 0, 0 }, 0 };
static const Foo * FooZero = &BarZero.foo; // if that is possible, untested...

В первом случае вам нужно будет получить доступ к компонентам BarZero.foo с помощью -> (например, BarZero.foo->a),

во втором случае вам придется обращаться к компонентам FooZero с помощью -> (например, FooZero->a).

1 голос
/ 12 сентября 2011

В языке C значение const или static const не считается "постоянной времени компиляции", тогда как

#define FooZero  {0, 0}

считается константой времени компиляции. Вы можете сказать: «Но, но это даже говорит const! Как это не может быть константой ??» И действительно, язык говорит, что вы не можете изменить значение вещи, которую вы указываете как const, но вы также не можете использовать ее в качестве инициализатора. Вы можете спросить, почему все, что вам нравится, не изменится так, как его определяет язык - хотя ваш компилятор может дать вам возможность изменить это поведение, и в любом случае это не так уж сложно обойти.

Я думаю, что для компиляторов C довольно распространено рассматривать статические константы как глобальные переменные, то есть фактически выделять пространство для переменной (которая никогда не изменяется), а не программировать жесткие значения в машинный код, как если бы Вы сделали #define. В этом случае константы, как говорит компилятор, не являются константами времени компиляции , хотя они являются константами для всех других целей после их инициализации (во время выполнения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...