在C语言中,给结构体分配常量值。

3
这是一个结构体数组,其中的元素被声明为const
它还通过在头文件中使用extern关键字作为全局变量传递。
// foo.h file
typedef enum
{
    A = 0,
    B,
    C,
    NAMES_MAX,
} Names_t;

typedef struct
{
    const int x;
    const int y;
} Foot_t;

// my global array.
extern const Foot_t FOO[NAMES_MAX];

// foo.c file
const Foot_t FOO[NAMES_MAX] =
{
    [A] = { .x = 1, .y = 1 },
    [B] = { .x = 2, .y = 2 },
    [C] = { .x = 3, .y = 3 },
};

我使用Names_t作为结构体FOO的索引。
现在我尝试使用我的全局结构体给另一个结构体赋值。
// bar.c file
typedef struct
{
    const int x;
    const int y;
    // more members here.
} Bar_t;

static Bar_t BAR =
{
    .x = FOO[A].x,
    .y = FOO[A].y,
};

但是我遇到了一个错误initializer element is not constant in C。 我知道这个错误的意思,FOO实际上不是一个常量表达式,就像在C++中那样。
问题是如何在保持上述结构的情况下解决这个错误?

为什么你不能直接使用FOO,而要在当前使用BAR的地方呢? - undefined
因为酒吧里有更多的成员。感谢您的输入。我已经修改了我的例子。 - undefined
你可以从BAR中移除其中的一些,然后同时使用FOO和BAR,或者用int const* const指针替换这些值,这些指针是可以初始化的(= &Foo[A].x)。虽然对我来说,指针间接引用是否更好看还有待商榷。你也可以使用#define来定义这两个相关的值,并用它们来初始化所有四个变量。 - undefined
1
这是一个常见问题。你实际上只是在问为什么 static int x=0; static int y=x; 这样的写法是不可能的。有很多重复的问题,我懒得去找一个。 - undefined
C23将添加constexpr存储说明符,使得可以将FOO用作编译时常量。 - undefined
3个回答

3

在文件范围内声明的对象或使用关键字static声明的对象,即具有静态存储期的对象,必须使用常量表达式进行初始化,并且另一个值的值(无论是否声明为const)不是这样的表达式。您需要明确初始化这些值。

此外,将struct的成员声明为const不是一个好主意。这可能会在尝试使用该结构时引发问题。最好将特定实例声明为const而不是成员,例如:

typedef struct
{
  int x;
  int y;
}Foot_t;

const Foot_t FOO[NAMES_MAX] =
{
  [A] = { .x = 1, .y = 1},
  [B] = { .x = 2, .y = 2},
  [C] = { .x = 3, .y = 3},
};

是的,我也将结构体 Foo_t 声明为 const,我忘记在示例中添加它了。刚刚添加进去了。 - undefined
1
你最好将特定实例声明为const,而不是成员,例如:这是一个非常糟糕的建议。它必须根据应用程序的需要进行声明。例如,表示硬件寄存器的结构体可能具有只读成员,但整个结构体不是可读写的。 - undefined

1
你的错误与 `const` 关键字无关,因为无论你是否添加 `const`,`FOO` 都不是一个常量表达式。 我看到两个解决方法:
1. 你可以使用宏来初始化 `FOO` 和 `BAR`,宏是常量表达式。
// foo.h file
#define FOO_A_X (1)
//...

// foo.c file
const Foot_t FOO[NAMES_MAX] =
{
  [A] = { .x = FOO_A_X, .y = FOO_A_Y},
  [B] = { .x = FOO_B_X, .y = FOO_B_Y},
  [C] = { .x = FOO_C_X, .y = FOO_C_Y},
};
//...

// bar.c file
// ...
static Bar_t BAR =
{
  .x = FOO_A_X,
  .y = FOO_A_Y,
};

你在运行时初始化了BAR,这有点糊弄人,因为你将其成员声明为const。
// bar.c file
// ...
#include <string.h>
static Bar_t BAR;

void Bar_Initializer(void)
{
   memcpy((void*)&BAR, &FOO[A], sizeof BAR);
}

3
这有点取巧,因为将数据复制到一个常量变量中是未定义行为,所以非常取巧。 - undefined
正确。使用需谨慎。 - undefined

0
一种简单的方法是定义FOO初始化常量:
#define FOO_A_x 1
#define FOO_A_y 2
...

使用这些值来初始化两个结构体:
const Foot_t FOO[NAMES_MAX] =
{
  [A] = { .x = FOO_A_x, .y = FOO_A_y},
  ...
};

...

static Bar_t BAR =
{
  .x = FOO_A_x,
  .y = FOO_A_y,
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接