C语言中的静态数组初始化

3

我正在阅读Yashavant Kanetkar的书《让我们一起学C语言》

在指针数组章节中,有一段代码给我带来了问题:

int main()
{
    static int a[]={0,1,2,3,4}; //-----------(MY PROBLEM)
    int *p[]={a,a+1,a+2,a+3,a+4};
    printf("%u %u %d\n",p,*p,*(*p));
    return 0;
}

我不理解为什么数组a必须初始化为静态的。我试过不用静态关键字来初始化它,但是我收到一个错误提示,“非法”。请帮我解决这个问题。

4
你获得了什么错误? - Alok Save
编译和运行对我来说都很好。你确定这是你问题的源头吗? - obataku
@Yunus static 表示指定了 a 具有静态存储,所以当作指针处理时它是一个编译时常量表达式。在 C90 中,数组(作为聚合类型)的初始化程序需要常量表达式。 - obataku
好的兄弟...非常感谢...还有一件事...因为我是新手,所以我正在使用Turbo C++ IDE...你能告诉我C90之类的意思吗? - Yunus
@Yunus:请放弃使用turbo C,你正在使用一个过时的编译器。C90是1990年发布的C标准,而最新的C标准是2011年发布的(C11)。这意味着你正在使用一个比最新的C标准早十年的编译器,已经落后于时代了。 - Alok Save
显示剩余5条评论
2个回答

5

C90 (6.5.7)规定:

具有静态存储期的对象的初始化程序中的所有表达式,或具有聚合类型或联合类型的对象的初始化列表中的所有表达式都应为常量表达式。

在您初始化具有聚合类型的对象时,该值必须在编译时已知,并且此情况下自动变量的地址不在其中。

请注意,这在C99(6.7.8 / 4)中已更改:

具有静态存储期的对象的初始化程序中的所有表达式都应为常量表达式或字符串字面值。

针对具有聚合或联合类型的对象的限制已被移除,我没有发现它被放置在其他地方。移除static关键字后,您的代码应该可以被C99编译器接受(例如,通过gcc -std=c99),这似乎确认我没有忽略其他限制。


C99的6.7.8/7条款如何解释这个问题?它难道没有说明正在初始化的对象是静态的情况吗? - phoxis
a 声明了 static 存储类型,所以 a 应该是一个地址常量(因此是一个常量表达式),a+1 等等应该是算术常量表达式。据我所知,这也被 C90 所接受。 - obataku
哇!这是否意味着要精通C语言,我们还必须详细了解所有这些东西? - Yunus
1
我的理解是OP想知道为什么需要静态变量。C90需要,但C99不需要。 - AProgrammer
明白了,但是6.7.8/8如何帮助解释这件事呢?编辑:明白了。 - phoxis
@veer,再次强调,OP(使用static)展示的代码在C90中是有效的。如果你移除了static,在C90中它就无效了,但在C99中是有效的。 - AProgrammer

2

我猜测数组初始化器的内容必须是编译时常量。在函数中使用 static 关键字相当于将局部变量变为全局变量,只不过作用域仍然是局部的。


你能否详细说明一下吗? - Yunus
编译器出现“非法初始化”错误...而且还有5个错误。 - Yunus
编译时常量是什么意思? - Yunus
编译器出现“非法初始化”错误...还有5个错误。在C语言(尤其是C++)中,通常建议忽略除第一个错误以外的所有错误,因为它们很可能只是后续错误。编译时常量是可以在编译时完全计算的表达式。如果astatic,编译器已经知道了它的地址(因为它必须为它分配空间),所以它是常量。如果它不是static,那么它就是指向堆栈上某个位置的指针,因此并不真正是常量。 - Joey
@Joey 但编译器难道不也知道其他变量的地址吗,例如一个“int”……甚至对于数组它也知道基地址对吧?请解释一下。 - Yunus
显示剩余4条评论

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