在C中初始化全局结构

时间:2010-03-26 08:35:02

标签: c struct constants initialization

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

当我尝试编译上面的代码时,编译器会报告以下错误:

“初始化元素不是常数”

坏线是这一行:

struct A a = createA(42);

有人可以解释什么是错的吗?我不是很有经验C.谢谢!

6 个答案:

答案 0 :(得分:16)

struct A a = { .x = 42 };

更多成员:

struct Y {
    int r;
    int s;
    int t;
};

struct Y y = { .r = 1, .s = 2, .t = 3 };

您也可以

struct Y y = { 1, 2, 3 };

同样适用于工会,您不必包含所有成员,甚至不必按正确顺序排列。

答案 1 :(得分:14)

为什么不使用静态初始化?

struct A a = { 42 };

答案 2 :(得分:4)

这里的问题是C中的全局/文件静态变量必须在编译时具有已知值。这意味着您无法使用用户定义的函数来初始化该值。它必须是一个常量表达式

答案 3 :(得分:2)

您不能像这样在静态初始化中调用函数。在您的示例中,您只需使用:

struct A a = {42};

如果你有一个更复杂的设置,你需要提供一个库构造和库销毁功能,你强迫你的库的用户调用(假设你想要可移植),或者你将不得不使用C ++并采取构造函数/析构函数的优点,或者你必须利用非标准和非可移植的__attribute __((构造函数))来创建一个在启动时运行的函数来初始化它。

如果您的设置更复杂,我强烈建议您使用C ++:

class A
{
   A(){
      // can do initialization in the constructor
   }
   // ...
};

A a;

但是,如果您需要坚持使用纯C,那么可移植的事情就是使用:

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

基本上,在上文中,您将使用mylibrary_init初始化您的库,并使用mylibrary_destroy拆分您的库。使用库的函数需要初始化的mylibrary_t实例,因此创建main函数的人员将负责调用mylibrary_init。使初始化函数依赖于“attributes”参数也是很好的,该参数可以替换为0或NULL作为默认值。这样,如果您扩展库并需要接受配置选项,则可以使用它。不过,这更像是一种设计而非技术方法。

答案 4 :(得分:2)

对于同样使用MSVC的好奇人士:

在C语言中,可以在main之前运行初始化函数,就像在C ++中一样(当然,如果在C语言中不可能,C ++会怎么做),但是如果你可能有点混乱还没有看到你的运行时库是如何工作的。

长话短说:

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

所以它不像C ++那样紧凑的源文本,但它可以做到。此外,在使用之前,我建议首先了解PE格式,然后在MSVC安装目录中读取crt \ src \ crt0.c和crt \ src \ crt0dat.c(在两个文件中搜索_cinit),以便了解发生了什么。

答案 5 :(得分:1)

您无法将函数称为初始值设定项。你需要在main中调用它。