问题
What is the best way to accomplish the following in C?
#include <stdio.h>
struct A
{
int x;
};
struct A createA(int x)
{
struct A a;
a.x = x;
return a;
}
struct A a = createA(42);
int main(int argc, char** argv)
{
printf("%d\n", a.x);
return 0;
}
When I try to compile the above code, the compiler reports the following error:
"initializer element is not constant"
The bad line is this one:
struct A a = createA(42);
Can someone explain what is wrong? I'm not very experienced in C. Thanks!
回答1:
Why not use static initialization?
struct A a = { 42 };
回答2:
struct A a = { .x = 42 };
More members:
struct Y {
int r;
int s;
int t;
};
struct Y y = { .r = 1, .s = 2, .t = 3 };
You could also do
struct Y y = { 1, 2, 3 };
The same thing works for unions, and you don't have to include all of the members or even put them in the correct order.
回答3:
The problem here is that global / file static variables in C must have a value known at compile time. This means you can't use a user defined function to initialize the value. It must be a constant expression
回答4:
You cannot invoke functions in static initialization like that. In your example, you can simply use:
struct A a = {42};
If you have a more complicated setup, you will need to provide a library construction and library destruction function that you force users of your library to call (assuming you want to be portable), or you will have to use C++ and take advantage of constructors/destructors, or you will have to take advantage of the non-standard and non-portable __attribute__((constructor)) to create a function that is run on startup to initialize it.
If you have more complicated setup, I would strongly advocate that you use C++:
class A { A(){ // can do initialization in the constructor } // ... }; A a;
However, if you need to stick with pure C, the portable thing to do is use something like:
typedef void* mylibrary_attr_t; typedef void* mylibrary_t; #ifdef __cplusplus # define EXTERNC extern "C" #else # define EXTERNC #endif EXTERNC int mylibrary_attr_init(mylibrary_attr_t*); EXTERNC int mylibrary_attr_setparam1(mylibrary_attr_t,int); EXTERNC int mylibrary_attr_setparam2(mylibrary_attr_t,double); // .. more functions for various attributes used by library EXTERNC void mylibrary_attr_destroy(mylibrary_attr_t*); EXTERNC int mylibrary_init(mylibrary_t*,mylibrary_attr_t); EXTERNC void mylibrary_destroy(mylibrary_t*); // functions that use mylibrary_t // ...
Basically, in the above, you would initialize your library with mylibrary_init
and teardown your library using mylibrary_destroy
. The functions using your library would require an initialized instance of mylibrary_t
, and so the person who created the main function would be responsible for invoking mylibrary_init
. It is also good to make the initialization function dependent on an "attributes" parameter that can be replaced with 0 or NULL as a default. That way, if you extend your library and need to accept configuration options, it is available to you. That's more a design than technical approach, though.
回答5:
For curious people who also use MSVC:
In C it is possible to run initialization functions before main just as it is possible in C++ (of course it is, how would C++ do it if it wasn't possible in C), however it may be somewhat confusing if you haven't read how does your runtime library work.
Long story short:
#pragma section(".CRT$XIU",long,read)
int
init_func ()
{
// initialization
return 0; // return 0 is mandatory
}
__declspec(allocate(".CRT$XIU"))
int (*global_initializer)() = init_func;
So it's not as compact source text as in C++, but it can be done. Also, before using I recommend to understand PE format first, then read crt\src\crt0.c and crt\src\crt0dat.c (search for _cinit in both files) in your MSVC installation directory so you know what is going on.
回答6:
You can't call a function as an initiliazer. You need to call it inside main.
来源:https://stackoverflow.com/questions/2521927/initializing-a-global-struct-in-c