【发布时间】:2019-11-26 11:54:25
【问题描述】:
我正在使用以下标志(其中 cc 是 gcc 4.2 或 clang 8.0):
$ cc -Wall -Werror -pedantic -ansi -std=c89 main.c
(我知道在这种情况下 -ansi 标志有点多余)
以下给出了我预期的错误
main.c:31:8: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
vec3 abc = {0};
int main()
{
vec3 a = {0};
vec3 b = {0};
Vec3(2, 2, 2);
vec3 abc = {0}; // Declared after a function call
return 0;
}
但是,以下不是
int main()
{
vec3 a = Vec3(0, 1, 2);
vec3 b = Vec3(0, 1, 2);
vec3 abc = {0}; // Declared after a function call
return 0;
}
确定用函数初始化变量仍然算作混合声明和代码?
Vec3 功能非常基础;没有设置内联标志等。
vec3 Vec3(float x, float y, float z)
{
vec3 rtn = {0};
rtn.x = x;
rtn.y = y;
rtn.z = z;
return rtn;
}
【问题讨论】:
-
这条规则没有意义,它被从语言中删除是有原因的。
-
@Lundin:如果一个实现将自动对象初始化器限制为编译时常量表达式,那可以简化单次编译器。该规则要做的另一件事是禁止分支到该对象生命周期内自动对象声明之前的位置,这会产生一些奇怪的极端情况。
-
@supercat 关于单次编译器,C++ 在 80 年代初删除了该规则,因此即使在过去也不是什么大问题。关于分支,正确的解决方案是移除向上的非条件分支。此外,这符合 C90:
fail: { int x = 5; goto fail; }。更别提 setjmp 了。 -
@Lundin:C++ 一直被设计为需要多遍编译。在未声明对象的块之前进行分支不会产生有问题的极端情况,因为分支结束了对象的生命周期。给定
void test(short i=0; loop: i++; int j=i; if (j < 10) goto loop; }之类的东西,j的存储值在其生命周期内会发生变化吗?这是否意味着以改变它的方式访问存储的?是否有任何int类型的左值表达式用于修改j?请注意,setjmp可以与自动持续时间对象进行奇怪的交互。
标签: c declaration c89 statements