在类C语言中,我们习惯于使if语句类似于以下内容:
if(x == 5) {
//do something
}
else if(x == 7) {
//do something else
}
else if(x == 9) {
//do something else
} else {
//do something else
}
我的问题是,编译器是否看到if语句,或者它最终被解释为:
if(x == 5) {
//do something
}
else {
if(x == 7) {
//do something
}
else {
if(x == 9) {
//do something
}
else {
//do something else
}
}
}
编辑:我意识到虽然这个问题在我脑海中是有道理的,但对于普通民众的其他人来说,这听起来可能相当愚蠢。我更多地指的是AST的外观以及是否存在'else-if'语句的特殊AST情况,或者它是否会被编译为级联if / else块。
答案 0 :(得分:17)
它们等同于C编译器。 C中没有特殊语法else if
。第二个if
只是另一个if
语句。
为了更清楚,根据C99标准,if语句被定义为
selection-statement:
if (expression) statement
if (expression) statement else statement
switch (expression) statement
,复合语句定义为
compound-statement:
{block-item-list(opt) }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
当编译器frond-end尝试理解源代码文件时,它通常遵循以下步骤:
然后将树传递给编译器中端(优化)或后端(生成机器代码)
在你的情况下这个if语句
if(x == 7) {
//do something else
} else if(x == 9) {
//do something else
} else {
//do something else
}
在selection-statement中被解析为selection-statement,
selection-stmt
/ | \
exp stmt stmt
| | |
... ... selection-stmt
/ | \
exp stmt stmt
| | |
... ... ...
和这一个
if(x == 7) {
//do something else
} else {
if(x == 9) {
//do something else
} else {
//do something else
}
}
与selection-statement中的复合语句内的选择语句相同:
selection-stmt
/ | \
exp stmt stmt
| | |
... ... compound-stmt
|
block-item-list
|
block-item
|
stmt
|
selection-stmt
/ | \
exp stmt stmt
| | |
... ... ...
所以他们有不同的AST。但它对编译器后端没有任何区别:正如你在AST中看到的那样,没有结构上的变化。
答案 1 :(得分:12)
在C和C ++中,将语句封装到冗余的{}
对中并不会改变程序的语义。这句话
a = b;
相当于这个
{ a = b; }
相当于这个
{{ a = b; }}
和这个
{{{{{ a = b; }}}}}
冗余{}
对编译器没有任何影响。
在您的示例中,第一个版本和第二个版本之间的唯一区别是您添加到后者中的一堆冗余{}
,就像我在上面的a = b
示例中所做的那样。你的冗余{}
一无所获。您提供的两个代码版本之间没有明显差异,这使您的问题基本上毫无意义。
如果您打算询问其他问题,请澄清您的问题或更正代码。
答案 2 :(得分:1)
事实上,这两段代码完全相同。你可以通过认识到“if”语句的语法如下来了解为什么这是真的:
if <expression>
<block>
else
<block>
NOTE that <block> may be surrounded by curly braces if necessary.
因此,您的代码分解如下。
// if <expression>
if (x == 5)
// <block> begin
{
//do something
}
// <block> end
// else
else
// <block> begin
if(x == 7) {
//do something else
}
else if(x == 9) {
//do something else
} else {
//do something else
}
// <block> end
现在,如果你在“else”的区块周围放置花括号,就像语言所允许的那样,你最终得到了第二种形式。
// if <expression>
if (x == 5)
// <block> begin
{
//do something
}
// <block> end
// else
else
// <block> begin
{
if(x == 7) {
//do something else
}
else if(x == 9) {
//do something else
} else {
//do something else
}
}
// <block> end
如果你对所有“if else”条款重复这样做,你最终会得到你的第二个形式。这两段代码完全相同,编译器完全相同。
答案 3 :(得分:0)
更接近第一个,但问题并不完全适合。
编译程序时,会经历几个阶段。第一阶段是词法分析,第二阶段是句法分析。词法分析分析文本,将其分成标记。然后语法分析查看程序的结构,并构造一个抽象语法树(AST)。这是在编译期间创建的基础语法结构。
基本上,if和else-else和if-elseif-else语句最终都是由编译器构造成抽象语法树(AST)。
以下是ASTs的维基百科页面:https://en.wikipedia.org/wiki/Abstract_syntax_tree
编辑: 实际上,如果/ if else语句可能形成更接近AST内部第二个的东西。我不太确定,但如果它作为二叉树状条件分支结构在底层表示,我不会感到惊讶。如果您有兴趣深入了解它,可以对编译器理论的解析方面进行一些研究。
答案 4 :(得分:0)
请注意,尽管您的第一个语句是根据if-else“梯形图”约定缩进的,但实际上显示真正嵌套的“正确”缩进是:
if(x == 5) {
//do something
} else
if(x == 7) { // <- this is all one big statement
//do something else
} else
if(x == 9) { // <- so is this
//do something else
} else {
//do something else
}
缩进是空白;它对编译器没有任何意义。第一个else
后的内容是一个大if
语句。因为它只是一个声明,所以它不需要围绕它。当你问“编译器是否按照这种方式阅读”时,你必须记住,大多数空间都是微不足道的;语法决定了语法树的真正嵌套。