【问题标题】:Initializing an array of structs (compiler error: initializer element is not constant)初始化结构数组(编译器错误:初始化元素不是常量)
【发布时间】:2013-08-20 22:03:46
【问题描述】:

我正在尝试使用以下代码初始化 C 结构:

/* header file */

typedef struct _funky {
   int  func_id;  /* I know this should be intptr_t, but ignore for now ... */
   char func_name[MAX_FUNC_NAME_LEN];
} Funky;


double func1(double d1, double d2, double d3);
double func2(double d1, double d2, double d3);
double func3(double d1, double d2, double d3);
double func4(double d1, double d2, double d3);


/* .c file */
Funky fk[4] = {
                 {(int)func1, "func1"}, /* <- gcc barfs here ... */
                 {(int)func2, "func2"},
                 {(int)func3, "func3"},
                 {(int)func4, "func4"}
              };

当我尝试编译它(gcc 4.6.3)时,我收到以下错误:

error: initializer element is not constant
error: (near initializer for 'fk[0].func_id')

我该如何解决这个错误?

[[编辑]]

在与 ouah 进行了简短的交谈后,我找到了这个错误的原因 - 它与用于初始化数组的函数定义有关。一些定义在不同的翻译单元中,而另一些则在不同的模块中。所有这些都意味着(IIUC)函数不会在编译时定义。

没有编写初始化函数(这将需要在现有代码中进行大量修改)我不确定如何解决这个问题 - 我也不确定它是如何在以前版本的 gcc 下编译的。

【问题讨论】:

  • 它不应该是一个 intptr_t,它应该是一个正确的函数指针。为什么忽略它,因为这可能是您问题的核心?
  • @Mat:结构中的该字段也用于在部分代码中存储整数。我正在使用遗留代码,并且这个结构用于超过 5k 的文件 - 有时该字段存储一个 int,而其他时候,它包含一个原始 ptr。我能做的最好的就是将其更改为 intptr_t,这将需要对现有代码的主体进行最少的修改。
  • intptr_t 不能保证能够在不丢失信息的情况下保存函数指针值,尽管它很可能能够。 (可能uintptr_tintptr_t 更有意义。)
  • @KeithThompson 添加到此,如果实现是 POSIX,则可以保证。

标签: c gcc compiler-errors


【解决方案1】:

函数定义与问题无关。不过,func_id 使用的类型是。

考虑这段代码:

#include <stdint.h>
#define MAX_FUNC_NAME_LEN  6

typedef uintptr_t ptr_t;

typedef struct Funky
{
   ptr_t  func_id;  /* I know this should be intptr_t, but ignore for now ... */
   char func_name[MAX_FUNC_NAME_LEN];
} Funky;

double func1(double d1, double d2, double d3);
double func2(double d1, double d2, double d3);
double func3(double d1, double d2, double d3);
double func4(double d1, double d2, double d3);

Funky fk[4] = {
                 {(ptr_t)func1, "func1"}, /* <- gcc barfs here ... */
                 {(ptr_t)func2, "func2"},
                 {(ptr_t)func3, "func3"},
                 {(ptr_t)func4, "func4"}
              };

正如所写,使用uintptr_t,它可以在 Mac OS X 10.8.4(64 位编译)上的 GCC 4.8.1 下干净地编译。将ptr_t 的类型更改为int,您会收到一堆警告。问题是 64 位地址常量不适合 32 位 int,因此加载程序必须生成代码来截断地址,这使得它们不够恒定。使用 32 位编译,使用int 的代码也编译干净。

所以,使用足够大的类型(推荐uintptr_t)就可以了。 “我知道它应该是intptr_t,但暂时忽略”评论是你麻烦的根源;不要忽视它。

【讨论】:

  • +1 直接解决问题并提供详细解释。
【解决方案2】:
typedef _funky {
   int  func_id;  /* I know this should be intptr_t, but ignore for now ... */
   char func_name[MAX_FUNC_NAME_LEN];
} Funky;

这里缺少struct 关键字。

还有:

Funky fk[3] = {
                 {(int)func1, "func1"}, /* <- gcc barfs here ... */
                 {(int)func2, "func2"},
                 {(int)func3, "func3"},
                 {(int)func4, "func4"}
              };

您的数组中有3 元素,但您使用4 初始化程序对其进行了初始化。

正如 cmets 中所述,将函数指针转换为 int 可能是个坏主意。绝对不能保证函数指针值适合 int 对象。

【讨论】:

  • 我的错,我会更正我提交的代码。这不是我遇到问题的原因
  • @HomunculusReticulli 你看到最后的编辑了吗?我认为这是您的错误消息的原因。
  • @HomunculusReticulli 好的,对您的原始问题进行了另一个编辑。你确定你的程序中定义了宏MAX_FUNC_NAME_LEN,尝试使用像256这样的固定值来测试。也请在你的问题中使用一些有效的例子。
  • 是的,常量已定义。对之前示例代码中的错误深表歉意。
  • @HomunculusReticulli 好的,所以假设常量是大于或等于5int,那么您的代码 sn-p 是有效的,并且没有符合要求的编译器可以拒绝它。您的实际程序可能略有不同。您应该创建一个显示失败的独立测试用例。
猜你喜欢
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 2014-05-25
  • 2012-03-22
  • 2014-02-18
  • 2012-04-10
相关资源
最近更新 更多