如何允许在“else-if”之间使用标签?

AnA*_*ons 2 c winapi label gcc visual-c++

这是一个简单的示例(与特定平台无关):

#include <stdio.h>
int main()
{
    for(int i = 0; i < 3; ++i)
        if(i == 0) printf("1\n");
        else if (i == 1) goto checkfor2;
        else checkfor2: if(i == 2 || i == 1) printf("2\n");
}
Run Code Online (Sandbox Code Playgroud)

现场魔杖盒

我提出这个问题的原始 Windows 代码:

#include <Windows.h>
#include <stdbool.h>
main() //sample with Win32 API
{
    for (;;) //infinite loop for my main logic
        if (WaitForSingleObject(hEvent, 1) != WAIT_TIMEOUT, true) //#1 check for some event
            //oops set comma true to test this event code
        {
            //do something
            //but here it will loop infinte and wouldn't check for #3
            //so if something goes wrong I can't exit

            //so clever me did the following:

            goto checkforexit; //see label on #3 below
        }
        else if (WaitForSingleObject(hEvent2, 1) != WAIT_TIMEOUT) //#2 check for another event
        {
            //do something else
        }
        else checkforexit: /*wow in between else and if*/ if (GetAsyncKeyState(VK_BACK) & 0x8000 && GetAsyncKeyState(VK_CONTROL) & 0x8000) //#3 check for keyboard shortcut for exit
            exit(0); //termination code
}
Run Code Online (Sandbox Code Playgroud)

我很惊讶这有效 - 似乎原始else if和标签if都按预期工作 - 这怎么可能?

如果您在 C 标准中添加引用,我将不胜感激。

它适用于 gcc(在 wandbox 上测试过)和 MSVC。

Eri*_*hil 6

标签实际上是if声明的一部分;该if声明标。

C 2018 6.8 将语句(C 语言形式语法中的标记)定义为以下之一:

  • 标记语句
  • 复合语句
  • 表达式语句
  • 选择声明
  • 迭代语句
  • 跳转语句

if … else6.8.4 中定义的语句是选择语句的选项之一:

  • if ( 表达式 ) 语句 else 语句

如您所见,在 之后的else语句语句可以是标记语句,其中一种形式是“标识符 : 语句”。(其他形式使用casedefault标签作为switch声明。)

这不是妨碍编译器,因为它简单地包括控制从一个转移goto语句将标签作为其控制流图,其中已经包括的一部分,从跳跃这样ifelse(因为第一语句被跳过,如果表达是假的),从结束while循环的开始,从break语句到外面for声明,甚至可以从goto报表的内部标签whilefor循环。通过构建一个通用的控制流图,编译器能够处理任意控制流并且不关心“结构化编程”。结构化编程是一种帮助人类的工具,但软件可以在没有该工具的情况下处理任意情况。

您可以大量使用标签在函数内部任意跳转,但是当您跳转到声明了可变长度数组或其他可变修改类型的作用域时,就会出现问题。如果您这样做,C 标准不会定义行为,例如:

if (flag)
    goto label;
while (foo)
{
    int bar[n];
    label: // Error, delaration of `bar` is skipped.
    …
}
Run Code Online (Sandbox Code Playgroud)