12

I'm curious why the following code snippet doesn't compile:

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 };

It complains about the use of FooZero, stating that FooZero isn't a Compile-Time Constant

But isn't it? What am I not understanding here?

Obviously, I can simply replace the use of FooZero in the initializer with { 0, 0 } - my purpose in asking the question is not how to get around the problem - I'm trying to understand the underlying reason why FooZero is not, in fact, a compile-time constant.

Thanks

Steve
  • 31,144
  • 19
  • 99
  • 122
  • possible duplicate of [Error "initializer element is not constant" when trying to initialize variable with const](http://stackoverflow.com/questions/3025050/error-initializer-element-is-not-constant-when-trying-to-initialize-variable-wi) – Foo Bah Sep 12 '11 at 05:09
  • http://stackoverflow.com/questions/3025050/error-initializer-element-is-not-constant-when-trying-to-initialize-variable-wi/3025106#3025106 is a pretty good explanation, encapsulating what I was going to write – Foo Bah Sep 12 '11 at 05:10
  • @Foo Bah - Thanks for the link. However; my question is "why is this so". I feel the answer to the question you cited doesn't really answer my question of "why" - they only point out what I already know to be the case. – Steve Sep 12 '11 at 05:14
  • @Steve You can't get around without using a function in C ? Also FooZero is not compile time constant. That is what both the links say. – Pavan Yalamanchili Sep 12 '11 at 06:01
  • @Pavan; `Also FooZero is not compile time constant.` Yes, again, I know that. My question is WHY is that so? Why are the mechanics of the language such that this is true? – Steve Sep 12 '11 at 06:25

2 Answers2

13

It has mainly to do with initialization.

The initialized variables are usually not initialized by code which says "put this value to that location", but by a definition which loads a specific value range, the .data resp. .rodata segment, to the memory location where it is supposed to be. This is done by the OS file loader. (Strictly speaking, this is not a property of C, which doesn't know anything about that, but of the execution environment.)

That said, it is not possible to tell a part of this memory area to be copied from another one. But it would be possible that te compiler itselfs recognizes the intent of the declaration and puts the same values to diefferent locations. But that would probably be too much "guessing".

In your case: Wouldn't a pointer to FooZero maybe a better solution? The values are both the same...

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 };

Or the other way round:

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...

In the first case, you would have to access BarZero.foo's components with -> (like BarZero.foo->a),

in the second case you would have to access FooZero's components with -> (like FooZero->a).

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • Thank you for your comment about initialization. That's what I was looking for. In regards to your comment about the pointer - understood - however I need the entire structure to 'copy' during every assignment... so having a pointer to another structure, in this case, isn't what I'm going for - if somewhere someone mutates the values in the structure being pointed to, it would break the system. But point well taken. Thanks! – Steve Sep 12 '11 at 15:27
  • 1
    as they all are declared `const`, no one should (normally) be able to modify it. – glglgl Sep 13 '11 at 09:13
2

In the C language a const or static const value is not considered a "compile time constant", whereas

#define FooZero  {0, 0}

is considered to be a compile-time constant. You may say "But but, it even says const! How can it not be a constant??" And indeed the language says you cannot change the value of a thing you specify as const, but you also cannot use it as an initializer. You can ask why all you like, it won't change how the language defines it - although your compiler may give you an option to change this behaviour, and it is not too hard to work around in any case.

I think it is quite common for C compilers to treat static constants like global variables - that is, to actually allocate space for a variable (which never changes), rather than program the hard values into the machine code as it would if you did a #define. In this case the constants, indeed as the compiler says, are not compile-time constants, although they are constants for all other purposes after they are initialised (at runtime).

Brian L
  • 3,201
  • 1
  • 15
  • 15
  • Thanks for the response! --- `You can ask why all you like, it won't change how the language defines it.` True, but I may be edified by the answer. --- `although they are constants for all other purposes after they are initialised (at runtime).` Interesting. When, precisely are they initialized? Upon first use? --- Also, thank you for the `#define` pointer. – Steve Sep 12 '11 at 06:29
  • @Steve Thanks for the comment - I think your question about initialization has been answered well by glglgl - initialization happens when loading data into the program at startup. – Brian L Sep 14 '11 at 04:10