为什么在C / C ++中交织switch / for / if语句是有效的? [重复]

问题描述 投票:2回答:2
我正在阅读boost/asio/coroutine.hpp,无法理解BOOST_ASIO_CORO_REENTER和BOOST_ASIO_CORO_YIELD的实现。 的扩展形式

reenter (this) { yield .. yield .. }

似乎是交织在一起的switch / if / for语句。我想知道为什么这是有效的C代码?我写了类似的东西(如下所示),发现它可以使用gcc进行编译。

int main() { int a = 1; switch (a) case 0: if (1) a = 2; else case 1: for (;;) { case 3: break; } return 0; }

c++ c language-lawyer
2个回答
2
投票
从语法上讲,开关的主体只是一个语句(通常,但不一定是复合语句)

6.8

statement: labeled-statement compound-statement expression-statement selection-statement iteration-statement jump-statement

可能带有标签6.8.1

labeled-statement: identifier : statement case constant-expression : statement default : statement

示例:

switch(1) one: case 1: dothis();

如果是复合语句,则也可以递归地标记每个子语句。示例:

switch(x) { if(1) one: case 1: dothis(); else case 0: orthis(); /*fallthru*/ three: case 3: three(); }

[语法将case / default-标签和常规标签视为相同,只有语义检查才能验证case / default-标签在switch内。

在实现方面,所有内容都将编译为(平面)汇编。

例如

if(test) YesBranch; else ElseBranch;

展平为(伪汇编)

IF_NOT_THEN_GOTO(test, PAST_YES_BRANCH) YesBranch goto PAST_NO_BRANCH; NoBranch PAST_NO_BRANCH:;

并且没有理由不能标记这种平面代码中的任何内容。

[case / default标签也与常规标签一样,不同之处在于它们(也通常用于)计算的跳转。


2
投票
原因是switch statements不是结构化的控制流语句。相反,应该将它们视为静态调度的语法糖。调度意味着控制流被重定向,而静态意味着编译器知道将其重定向到的位置。

所以您的代码

int a = 1; switch (a) case 0: if (1) a = 2; else case 1: for (;;) { case 3: break; } return 0;

将被编译成大致等同于

int a = 1; void *dest = dispatch(a, { case0_addr, case1_addr, case3_addr }); goto *dest; case0_addr: if (1) { a = 2; } else { case1_addr: for (;;) { case3_addr: goto case_end; } } case_end: return 0;

其中dispatch是编译器运行的函数,用于发出静态分派所需的机器代码。由于所有调度值都是常量,并且编译器知道所有调度目标,因此它可以生成非常有效的机器代码。

关于为什么它是合法的,我想原因是因为没有特别的理由使它非法。如图所示,case语句只是转到标签,因此可以将它们放置在任何位置。

© www.soinside.com 2019 - 2024. All rights reserved.