我知道编译器的行为不能真正证明任何事情,但我认为检查编译器的内部表示会给出什么会很有趣(仍然比汇编检查高一点)。
我使用了Clang/LLVM 在线演示和以下代码:
#include <stdio.h>
#include <stdlib.h>
struct X
{
X const& f(int i) const
{
printf("%d\n", i);
return *this;
}
};
int main(int argc, char **argv) {
int i = 0;
X x;
x.f(++i).f(++i).f(++i); // line 16
}
并使用标准优化(在 C++ 模式下)编译,它给出了:
/tmp/webcompile/_13371_0.cc:在函数'int main(int,char**)'中:
/tmp/webcompile/_13371_0.cc:16:警告:对'i'的操作可能未定义
我确实觉得很有趣(有其他编译器警告过吗?Comeau online 没有)
顺便说一句,它还产生了以下中间表示(向右滚动):
@.str = private constant [4 x i8] c"%d\0A\00", align 1 ; <[4 x i8]*> [#uses=1]
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
entry:
%0 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 3) nounwind ; <i32> [#uses=0]
^^^^^
%1 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 3) nounwind ; <i32> [#uses=0]
^^^^^
%2 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 3) nounwind ; <i32> [#uses=0]
^^^^^
ret i32 0
}
显然,Clang 的行为就像 gcc 4.xx 一样,在执行任何函数调用之前首先评估所有参数。