无效指令的解释
Interpretation of instructions without effect
我们如何解释下面的程序和它的成功?(很明显不能有任何错误信息)。我的意思是编译器如何解释 main 中的第 2 行和第 3 行?
#include <stdio.h>
int main()
{
int a,b;
a; //(2)
b; //(3)
return 0;
}
这就像你尝试这样的事情:
#include <stdio.h>
int main(void){
1;
2;
return 0;
}
正如我们所见,这里有两个表达式,后跟分号(1; 和 2;)。根据语言规则,这是一个格式正确的语句。
没毛病,就是没用
但是,如果您尝试使用 though 语句(a 或 b),则行为将是不确定的。
当然,编译器会将其解释为无效的语句
L.E:
如果你运行这个:
#include <stdio.h>
int main(void){
int a;
int b;
printf("A = %d\n",a);
printf("B = %d\n",b);
if (a < b){
printf("TRUE");
}else{
printf("FALSE");
}
return 0;
}
您将获得:
A = 0
B = 0
FALSE
因为a和b设置为0;
你的
a;
只是一个表达式语句。与在 C 中一样,对表达式语句中的完整表达式求值并立即丢弃其结果。
比如这个
a = 2 + 3;
是包含完整表达式 a = 2 + 3
的表达式语句。该表达式的计算结果为 5
,并且还具有将 5
写入 a
的副作用。结果被评估并丢弃。
表达式语句
a;
以同样的方式治疗,只是没有副作用。 由于您忘记了初始化变量,对上述表达式的求值可能会正式导致未定义的行为。
显然,实用的编译器会完全跳过此类表达式语句,因为它们没有可观察到的行为。
C 中的句子不是控制结构(if、switch、for、while、do while)或控制语句(break、continue、goto、return)是表达式。
每个表达式都有一个结果值。
对表达式的副作用进行评估(更改对象的值、写入文件、读取易失性对象以及执行其中一些操作的函数)。
这种表达式的最终结果总是被丢弃。
例如,函数 printf() return 是一个 int 值,一般不使用。然而这个值产生了,然后被丢弃了。
但是函数 printf() 会产生副作用,因此必须对其进行处理。
如果一个句子没有副作用,那么编译器完全可以随意丢弃它。
我认为对于编译器来说,检查一个句子是否没有任何副作用并不难。因此,在这种情况下,您可以预期编译器将选择不执行任何操作。
此外,这不会影响程序的可观察行为,因此在程序执行结果中获得的内容没有区别。但是,当然,如果编译器完全忽略任何计算,程序将 运行 更快。
另请注意,在某些情况下,浮点环境可以设置标志,这被认为是副作用。
Standard C (C11) 表示,作为第 5.1.2.3p.4 段的一部分:
An actual implementation need not evaluate part of an expression if it
can deduce that its value is not used and that no needed side effects
are produced [...]
结论: 必须阅读自己正在使用的特定编译器的文档。
这就是为什么你应该使用一些编译警告标志!
-Wall 会触发 "statement with no effect" 警告。
如果您想查看编译结果,请使用 -S 进行编译。
用你的代码试试,with/without -O(优化)标志...
我们如何解释下面的程序和它的成功?(很明显不能有任何错误信息)。我的意思是编译器如何解释 main 中的第 2 行和第 3 行?
#include <stdio.h>
int main()
{
int a,b;
a; //(2)
b; //(3)
return 0;
}
这就像你尝试这样的事情:
#include <stdio.h>
int main(void){
1;
2;
return 0;
}
正如我们所见,这里有两个表达式,后跟分号(1; 和 2;)。根据语言规则,这是一个格式正确的语句。
没毛病,就是没用
但是,如果您尝试使用 though 语句(a 或 b),则行为将是不确定的。 当然,编译器会将其解释为无效的语句
L.E:
如果你运行这个:
#include <stdio.h>
int main(void){
int a;
int b;
printf("A = %d\n",a);
printf("B = %d\n",b);
if (a < b){
printf("TRUE");
}else{
printf("FALSE");
}
return 0;
}
您将获得:
A = 0 B = 0 FALSE
因为a和b设置为0;
你的
a;
只是一个表达式语句。与在 C 中一样,对表达式语句中的完整表达式求值并立即丢弃其结果。
比如这个
a = 2 + 3;
是包含完整表达式 a = 2 + 3
的表达式语句。该表达式的计算结果为 5
,并且还具有将 5
写入 a
的副作用。结果被评估并丢弃。
表达式语句
a;
以同样的方式治疗,只是没有副作用。 由于您忘记了初始化变量,对上述表达式的求值可能会正式导致未定义的行为。
显然,实用的编译器会完全跳过此类表达式语句,因为它们没有可观察到的行为。
C 中的句子不是控制结构(if、switch、for、while、do while)或控制语句(break、continue、goto、return)是表达式。
每个表达式都有一个结果值。
对表达式的副作用进行评估(更改对象的值、写入文件、读取易失性对象以及执行其中一些操作的函数)。
这种表达式的最终结果总是被丢弃。
例如,函数 printf() return 是一个 int 值,一般不使用。然而这个值产生了,然后被丢弃了。
但是函数 printf() 会产生副作用,因此必须对其进行处理。
如果一个句子没有副作用,那么编译器完全可以随意丢弃它。
我认为对于编译器来说,检查一个句子是否没有任何副作用并不难。因此,在这种情况下,您可以预期编译器将选择不执行任何操作。
此外,这不会影响程序的可观察行为,因此在程序执行结果中获得的内容没有区别。但是,当然,如果编译器完全忽略任何计算,程序将 运行 更快。
另请注意,在某些情况下,浮点环境可以设置标志,这被认为是副作用。
Standard C (C11) 表示,作为第 5.1.2.3p.4 段的一部分:
An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced [...]
结论: 必须阅读自己正在使用的特定编译器的文档。
这就是为什么你应该使用一些编译警告标志! -Wall 会触发 "statement with no effect" 警告。
如果您想查看编译结果,请使用 -S 进行编译。 用你的代码试试,with/without -O(优化)标志...