initializing array of structure with array elements in it - c

#include <stdio.h>
int main()
{
typedef struct s
{
int a;
int b[5];
char c[2];
}st;
st vs[1];
vs[0] = {1,{1,2,3,4,5},{'c','d'}};
printf("%d:a\n",vs[1].a);
printf("%d:b[0]\t %d:b[4]\n",vs[0].b[0],vs[0].b[4]);
printf("%c:c[0]\t %c:c[1]\n",vs[0].c[0],vs[0].c[1]);
return 0;
}
why does this doesn't work?
on
gcc -o main *.c
I get this error
main.c: In function 'main':
main.c:15:12: error: expected expression before '{' token
vs[0] ={1,{1,2,3,4,5},{'c','d'}};
But if I have this:
#include <stdio.h>
int main()
{
typedef struct s
{
int a;
int b[5];
char c[2];
}st;
st vs[] = {
{1,{1,2,3,4,5},{'c','d'}}
};
printf("%d:a\n",vs[0].a);
printf("%d:b[0]\t %d:b[4]\n",vs[0].b[0],vs[0].b[4]);
printf("%c:c[0]\t %c:c[1]\n",vs[0].c[0],vs[0].c[1]);
return 0;
}
it works. What is the logic in this.
How can I make it work using st vs[1] method?

You can only do braced initialization when you declare a variable. So,
st vs[] = {
{1,{1,2,3,4,5},{'c','d'}}
};
is allowed. But
vs[0] = {1,{1,2,3,4,5},{'c','d'}};
is not. Because this is not a initialization but assignment.
However, you can use C99's compound literal, see C11, 6.5.2.5:
vs[0] = (struct s){1,{1,2,3,4,5},{'c','d'}};

Initialization is when you declare a variable and provide initial values for it as part of the declaration. For example this is legal:
st vs[1] = { {1,{1,2,3,4,5},{'c','d'}} };
Your code is actually attempting assignment. Assignment is when an existing variable has a value assigned to it. The reason your code doesn't work is that {1,{1,2,3,4,5},{'c','d'}} isn't a value.
In a statement (not a declaration), each expression must be readable by the compiler on its own merit, and a more complicated statement is made up of various expressions joined by operators. So the compiler doesn't know what to do with {1,{1,2,3,4,5},{'c','d'}} - at this stage it has no idea that that is supposed to be a st.
Since C99 there is a new language construct you can use here, called compound literal:
vs[0] = (const st){1,{1,2,3,4,5},{'c','d'}};
Note that this is not a cast operator being applied to some sort of braced expression; it is a single syntactic construct (Typename){ initializers } .
My use of const is a micro-optimization, it may help the compiler store the literal in a read-only block of the executable and allow constant folding.

Related

the difference of const initializer for global and local variable in C [duplicate]

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
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;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
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;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in 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;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#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;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.

Why can static variables be initialized with only constant literals? [duplicate]

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
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;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
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;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in 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;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#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;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.

gcc compiler says constant variables are not constant [duplicate]

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
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;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
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;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in 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;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#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;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.

Array initialization giving error: initializer element is not constant [duplicate]

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
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;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
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;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in 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;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#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;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.

Error "initializer element is not constant" when trying to initialize variable with const

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
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;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
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;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in 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;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#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;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.

Resources