【问题标题】:gcc complains: variable-sized object may not be initializedgcc 抱怨:可变大小的对象可能未初始化
【发布时间】:2012-04-25 03:26:39
【问题描述】:

我看过这些,但他们没有回答我的问题:

variable-sized object may not be initialized

C compile error: "Variable-sized object may not be initialized"

Error: Variable-sized object may not be initialized. But why?


我正在尝试编写一些相当便携的 c 代码:

int main () 
{
    const int foo=13;
    int bar[foo]={0};
    return 0;
}


使用以下任一方法编译为c 代码时出现variable-sized object may not be initialized 错误:

  • gcc 4.3.4
  • arm-linux-gnueabi-gcc 4.4.5

如果我在 VS2008 中将其编译为 c,我会得到一个略有不同的 error C2057: expected constant expression


我了解到,c 代码编译器无法将 const int foo=13; 识别为真正的常量;例如我们可能有

void a(int fool) 
{    
    const int foo=fool;
    int bar[foo]={0};
}


我也意识到unlike the gcc compilersVS2008编译器没有C99 variable-length arrays的概念。而且那个 MS 显然没有提到任何未来的支持。


然而,cpp 代码编译与 gccMS 编译器完全不同/更聪明?!


关于 gcc c 代码编译器我不明白的地方是:


(注意:在最后一种情况下,MS c 代码编译失败;与 int bar[foo]={0}; 一致)

【问题讨论】:

  • 在我的 TDM-GCC 4.6.1 上,最后一个示例 not 编译(同样是“可变大小的对象可能未初始化”)。我也从未听说过由初始化列表初始化的 VLA,这甚至是正确的 C 吗?调查它..
  • 对于您关于 MS 编译器的部分问题,这不是唯一缺少的功能,它们根本不支持 C99。从去年开始,甚至还有一个更新版本的标准 C11,所以他们现在缺少 2 个主要版本。
  • @anthales,谢谢。嗯..
  • ..关于 VLA 初始化问题,我同意你的看法——这就是我在 cpp 编译测试中投入的原因。
  • 通过查看 C++ 编译器的功能来尝试理解 C 问题绝不是一个好主意——据我所知,C++ 甚至没有 VLA,但这只是来自的 GNU 扩展海湾合作委员会。如果您真的需要知道您是否正在编写合法的 C 代码,请选择您的 C 标准 here。现在已经接受 Mats 的回答了 ;)

标签: c gcc gcc4


【解决方案1】:

C99 §6.7.8 初始化这样说:

要初始化的实体的类型应该是一个未知大小的数组或一个不是可变长度数组类型的对象类型。

所以你的初始化是无效的 C.

type a[size]成为 VLA 的唯一方法是 size 成为 整数常量表达式(第 6.7.5.2 节)。你所拥有的不是整数常量表达式,所以你有一个 VLA:

如果大小不存在,则数组类型是不完整类型。如果大小是 * 而不是表达式,则数组类型是未指定大小的可变长度数组类型, 只能在具有函数原型范围的声明中使用,这样的数组是 尽管如此完整的类型。如果大小是整数常量表达式并且元素类型具有已知的常量大小,则数组类型不是变长数组类型; 否则,数组类型为变长数组类型。

第 §6.6/6 部分 常量表达式 将它们定义为:

一个整数常量表达式应该是整数类型并且应该只有操作数 即整数常量、枚举常量、字符常量、sizeof 结果是整数常量和浮点常量的表达式 强制转换的直接操作数。整数常量表达式中的强制转换运算符只能 将算术类型转换为整数类型,但作为 sizeof 操作数的一部分除外 运算符。

【讨论】:

  • 好的。所以foo+1 不能是整数常量表达式,因为在编译时不可能肯定知道foo 的值,即使它被声明为const。所以这是我的 gcc 中的一个错误。
  • 有趣的是,clang 支持 foo+1 作为扩展:clang.llvm.org/docs/UsersManual.html#c_ext
  • 为什么在ideone.com/Br6cC 中,数组bar 被视为VLA 仍然在困扰我。因为可以在编译时确定foo 确实是一个整数常量。事实上,我倾向于找出为const int foo=13;之类的东西实际生成了什么样的汇编代码
  • 编译器是否可以确定它是否是编译时常量并不重要,标准要求使用整数常量表达式,const int 值不是一个。 (C++ 有更复杂的规则 constexpr,但我相信没有 VLA。)
【解决方案2】:

其实,对于我的 gcc(4.4.4 版),你的最后一个例子

int main()
{
    const int foo=13;  
    int bar[foo+1]={0}; //wtF?
    return 0;
}

编译,正如人们所期望的那样。您可能需要仔细检查您的工具链(以确认您没有在某处重新链接现有的“.o”),然后重试。

如果您发现它确实有效,这是我的gcc -v 输出,也许您可​​以检测到配置中的差异,这可能会有所帮助。

Using built-in specs.
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.4.4 20100630 (Red Hat 4.4.4-10) (GCC) 

【讨论】:

  • 好吧,我得到了this 〜不太确定我应该寻找什么 tbh - 看起来我可能会遇到另一个 debian 挤压稳定 效果
  • 我仍然不明白为什么cpp 有效但c 无效。我的意思是我可以看到cpp 编译器具有不引发错误所需的所有信息。但是是否有一些 c 标准专门用于 * 行为方式不同?
  • @violet313,我的帖子是cpp 不起作用。显然,您使用的是不同的编译器,甚至只是 cpp 的不同配置副本。如果允许您编译,您正在使用的那个就不能正常工作;这是该编译器中的一个错误(如果您关心可移植性,即使您的编译器允许,也不应该使用这样的结构)。
  • Edwin。是的,我确实关心便携性。我用#define 修复了我的代码,好奇心驱使我来到这里。为您的时间 +1
  • 虽然我同意anthales ccpp 是不同的野兽,但你说cpp 编译对你来说不起作用,我也有this code @987654336 @在VS2008下编译。 & 注意 MS *不做 VLA ;)
【解决方案3】:

由于 Matt 已经引用了标准,应用于整数变量的 const 限定符不算作整数常量表达式。我们可能想知道为什么?它看起来像一个整数常量一样无辜!

可能是因为const 不是绝对consts。您可能会通过指针更改它们的值,而编译器可能会做的所有事情,如果它捕捉到这样的赋值,就会抛出警告,但不能真正阻止您更改 const 值。

PS:不要相信在线编译器,如ideone.com 等。这是一个愚蠢的runtime error,它为一个非常简单的C 程序抛出。

【讨论】:

  • 哈哈。公平点,但我最初确实遇到了问题,然后在我的 debian squeeze 上编译测试 - 然后发现 ideone 编译器做了同样的事情 - 这似乎既方便又似乎使问题更相关
猜你喜欢
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多