C 与 C++ 开关语句变量定义与声明

C vs C++ switch statement variable definition vs declaration

提问人:asimes 提问时间:7/22/2015 最后编辑:asimes 更新时间:7/22/2015 访问量:1280

问:

我正在玩一些语法,发现了一些奇怪的编译器规则,想知道这样做的原因是什么

C 不会编译它,但 C++ 会

switch (argc) {
case 0:
    int foo;
    break;
default:
    break;
}

C 和 C++ 都将编译以下内容

switch (argc) {
case 0:
    ; int foo;
    break;
default:
    break;
}

C 将编译这个,但不会编译 C++

switch (argc) {
case 0:
    ; int foo = 0;
    break;
default:
    break;
}

gcc -v是如果它很重要。我意识到解决方案是用大括号包裹内容,但我对编译错误的原因更感兴趣gcc version 4.9.3 (MacPorts gcc49 4.9.3_0)case 0:

C++(英语:C++) c

评论

5赞 chris 7/22/2015
这个答案有些相关。
2赞 jaggedSpire 7/22/2015
如果您在附加语句中设置,则看起来第二种情况仍然适用于 c++。GCC 只是抱怨这个例子中未使用的变量,而 clang 对它很好。foo
1赞 asimes 7/22/2015
@chris,谢谢,第三种情况现在有点意义(无法跳过C++中的初始化)
0赞 chris 7/22/2015
我不明白为什么第一个是无效的 C.查看 C99,一个带标签的语句是标识符:语句,并且没有提到那里需要表达式(我仍然收到普通标签和没有开关的错误)。编辑:没关系,GCC更具描述性,并明确指出声明不是C语言中的语句。
1赞 sepp2k 7/22/2015
@chris 声明不是 C 语言中的语句(但它是 C++ 语言中的语句)。

答:

23赞 sepp2k 7/22/2015 #1
case 0:
    int foo;

在 C 和 C++ 中,带标签的语句都是后跟语句的标签。但是,在 C++ 中,语句的定义包括“块声明”(即可能出现在块中的声明和定义),而在 C 中则不包括(在 C 中,块是一系列“块项”,它们是块声明或语句 - 在 C++ 中,它是一系列语句,其中包括块声明)。

case 0:
    ; int foo;

这之所以有效,是因为在 C 和 C++ 中都是一个(n 空)语句,所以这里我们确实有一个标签后跟一个语句。;

case 0:
    ; int foo = 0;

正如注释中已经解释的那样,这在 C++ 中不起作用,因为 C++ 使跳过初始化成为非法的。

评论

0赞 asimes 7/22/2015
这是一个很好的答案,但第三种情况仍然是最让我困惑的情况。它是如何跳过初始化的?为什么将定义放在大括号内可以避免跳过初始化?
1赞 chris 7/22/2015
@asimes,当你加大括号时,是标记语句的语句。如果不这样做,则是开关的一部分,而不是案例的一个语句,因此它在下一个标签之外的范围内,但会跳过其初始化。{; int foo = 0;}int foo = 0;
0赞 sepp2k 7/22/2015
@asimes 它可能会跳过初始化,因为它可能会跳转到默认情况,即在范围内但未初始化。如果添加大括号,则不再在默认块的范围内。基本上,“跳过初始化”规则禁止您跳过具有初始值设定项的变量范围的“中间”。也就是说,您可以跳转到初始化或变量超出范围后跳转到初始化,但不能跳转到这些点之间的任何位置。foofoo
0赞 jaggedSpire 7/22/2015
如果可以的话:为什么分离 placate gcc 的声明和初始化,当初始化仍在 switch 语句中,并且至少被一种情况跳过时?foo
3赞 chris 7/22/2015
@jaggedSpire,分配不是初始化。您可以轻松地做到,而无需跳过任何内容。int i; foo(i); i = 0;