C 为什么开关(0)不产生警告,而如果(0)产生警告?

C 为什么开关(0)不产生警告,而如果(0)产生警告?,c,visual-studio-2012,gcc,clang,C,Visual Studio 2012,Gcc,Clang,鉴于此代码: #include <stdio.h> int main( int argc, char** argv ) { switch (0) { case 1: printf("1"); case 2: printf("2"); default: printf("default"); break; } return 0; } #包括 int main

鉴于此代码:

#include <stdio.h>

int main( int argc, char** argv )
{
    switch (0) { 
        case 1: printf("1"); 
        case 2: printf("2"); 
        default:
            printf("default");
            break; 
    }
    return 0;
}
#包括
int main(int argc,字符**argv)
{
开关(0){
案例1:printf(“1”);
案例2:printf(“2”);
违约:
printf(“违约”);
打破
}
返回0;
}
我希望编译器会告诉我关于条件表达式是常量(
switch(0)
,而VS2012会针对
if(0)
)或无法访问的代码(
case1
case2
)发出此警告

然而,无论是在Visual Studio 2012上,还是在最近的GCC上,我都没有收到类似的消息


为什么连体面的编译器都不抱怨呢?

我刚试过
clang-Weverything
:它抱怨没有使用
argc
argv
,但对
开关(0)
保持沉默,就像
gcc
一样

虽然编译器不必发出诊断,但如果错误是打字错误,则警告可能会有所帮助。试试这个例子:

int test(int l) {
    switch (1) {
    case 0: return 0;
    case 1: return 1;
    default: return -1;
}
您应该在两个项目上都提交一个bug


编辑:
clang
最近似乎已经解决了这个问题,与Ryker在回复中所显示的不同,
-Wunreachable code
不会在我的笔记本电脑上抱怨。我可能有一个较旧的版本。

我只是在打开“扩展警告”的情况下在CLANG上尝试了它,并收到以下警告:

奇怪的是,仅指交换机中两行中永远不会执行的第一行:

   case 1: printf("1"); 

要在Visual Studio 2013中获取警告,您需要:

  • 右键单击项目-->属性
  • “常规”部分中的C/C++将警告级别设置为“所有”
  • 该警告仅适用于if语句,因为开关是块

    来自:

    5.1.1.3诊断

    1一致性实施应产生至少一条诊断信息(在 一种实现定义的方式)如果是预处理翻译单元或翻译单元 包含违反任何语法规则或约束的行为,即使该行为也是显式的 指定为未定义或实现已定义诊断消息不需要显示 在其他情况下产生。9)
    9) 其目的是一个实现应该识别每一个的性质,并在可能的情况下进行本地化 违反当然,一个实现可以自由地生成任意数量的诊断,只要 有效的程序仍被正确翻译。它还可以成功地翻译无效的程序。 重点补充

    因此,如果在
    开关中使用常量表达式,或者如果
    控制表达式违反约束,则需要进行诊断

    6.8.4.1
    if
    语句 约束

    1
    if
    语句的控制表达式应具有标量类型。

    6.8.4.2
    开关
    语句


    约束

    1开关的控制表达式应为整数类型。

    2如果
    开关
    语句在 带有可变修改类型的标识符,整个
    开关
    语句应在 该标识符的范围。154)

    3每个
    案例
    标签的表达式应为整数常量表达式,且不得有两个 同一
    开关
    语句中的case常量表达式应具有相同的值
    转换后。switch语句中最多可以有一个
    default
    标签。 (任何封闭的
    开关
    语句都可能有
    默认值
    标签或
    大小写
    常量 表达式的值与封闭表达式中的
    大小写
    常量表达式重复
    开关
    语句。)
    154)也就是说,声明要么在
    开关
    语句之前,要么在最后一个
    大小写
    之后,或者
    default
    标签与包含声明的块中的
    开关关联。
    …事实并非如此


    这基本上是一个执行质量问题;实现可能会发出一个诊断,用于在
    if
    switch
    语句中使用常量表达式,但不必这样做<代码>如果(0)
    开关(0)
    可能会让我们大多数人觉得不可靠,但实现不需要对它们发出任何诊断

    你会期望这样的警告在实际代码中捕捉到很多bug吗?@KerrekSB:好吧,因为
    if(0)会导致一个警告(在VisualStudio中条件表达式是常量),我想这里应该是这样的,我想区别在于警告可能有用的频率。恒定
    if
    条件是很常见的;使用常量<代码>开关<代码>值的情况要少得多,几乎是“我不记得在野外见过一个”。但是,我可以看到它在某些上下文中可能很有用-
    switch(sizeof(somevar))
    后跟处理不同机器类型的代码(例如
    case2:…;break;case4:…;break;case8:…;break;default:assert(0);break;
    )。我不确定这是否好,但它可能是有效的。@chqrlie我试过
    gcc-Werror
    。没有警告/errors@ManosNikolaidis
    -Werror
    是一个骗局,它不会激活任何额外的警告,它只会使所有警告行为像错误一样。发生这种情况的原因很清楚:
    case
    标签只是标签,开关中的整个块永远不会被执行,因此
    clang
    只会对块发出警告,不是每句话都是如此。@xxl-当然。这是有道理的,只是执行了
    default
    case语句。这个答案说明了明显的-没有用。@anatolyg:which