2

I'm trying to define two const variables with the same data structure. I want to ensure that all of the members of each variable are exactly the same except for the one that I am changing. Since I do not want to maintain two exact copies of the same code, I thought "why not use the existing members in one to initialize the other?"

Here is an example in code:

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

const aStruct foo = {
    .a = 10,
    .b = 20
};

const aStruct bar = {
    .a = 15,
    .b = foo.b
};

When I try to compile this code, I get an error:

foo.c:13:14: error: initializer element is not constant
         .b = foo.b
              ^~~
foo.c:13:14: note: (near initialization for ‘bar.b’)

I'm fairly new to C, so I don't fully understand how constants and data structures work, especially when they are put together. Can someone help me figure out what is going on here?

Adam Gausmann
  • 302
  • 1
  • 10
  • 1
    Use a#define to share a value. – Jean-François Fabre Sep 04 '16 at 16:10
  • This is tricky territory, but I think the problem is that `const` isn't as constant as you'd like. At file scope (as opposed to function scope), you can't write: `static const int N = 100;` and `static aStruct as_array[N];` either; the value of N is not considered to be a compile-time constant and the array size must be a compile-time constant. You can often use addresses as initializers in similar circumstances because the address is fixed (by the linker — the last phase of 'compile-time' processing). But I think you're running into this "`const` isn't really constant" problem. – Jonathan Leffler Sep 04 '16 at 16:23
  • A corollary to what I was saying: you'd not be able to use `static aStruct as_data[foo.a];` either — in this case, neither at file scope nor function scope (but drop the `static` and it would be fine at function scope). See also [`static const` vs `#define` vs `enum` in C](http://stackoverflow.com/questions/1674032/). This is not a duplicate of that, but it may shed some light on the issue you're facing. – Jonathan Leffler Sep 04 '16 at 16:24
  • Your title already said it: "Assigning members of a const **variable** ...". C does not have symbolic constants (except enum-constants). – too honest for this site Sep 04 '16 at 16:44
  • You intention is perfectly clear: `foo.b` has already been initialized so why doesn't the compiler use that value? But note that `.b = foo.b` requires _instructions_ (get address of `foo`, add offset to `b`, get value of `b`) and instructions can only be executed in functions. – Paul Ogilvie Sep 04 '16 at 16:47

1 Answers1

2

This is because you are trying to initialize global variables at file scope, and at that scope only constants (foo.b is not) can be used to initialize values. My compiler gives a better message:

error: initializer element is not a compile-time constant
    .b = foo.b
         ~~~~^ 1 error generated.

If you had tried to do the same at block scope, that would have been correct:

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

int main() {
  const aStruct foo = {
    .a = 10,
    .b = 20
  };

  const aStruct bar = {
    .a = 15,
    .b = foo.b
  };
}

So, you'd better use some defines to initialize your global variables to the same value.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • I have a problem with that solution. Members of the struct in the actual application are structs themselves, so using #defines is pretty hard. However, it does answer the example I've given, so thanks! – Adam Gausmann Sep 04 '16 at 16:27
  • 1
    @AdamGausmann: there are compound literals and designated initializers that can be used `(struct WhatEver){ .we_member1 = VALUE1, .we_member3 = VALUE3 }` etc. That can be wrapped in `#define`. Or maybe you should use (constant) pointers to other (constant) structures? Or some combination. I'm not keen on `#define`, but if this is going to be repeated multiple times, using a macro to avoid repetition is a good idea. – Jonathan Leffler Sep 04 '16 at 16:32