问题描述
这是的代码变体,只是较短的一条,并且不会造成任何损害对新手来说。我们有以下代码:
It's a variation of code from this tweet, just shorter one and not causing any damage to noobs. We have this code:
typedef int (*Function)();
static Function DoSmth;
static int Return7()
{
return 7;
}
void NeverCalled()
{
DoSmth = Return7;
}
int main()
{
return DoSmth();
}
您会看到 NeverCalled()
不会在代码中调用,不是吗?这是当使用
选择clang 3.8时显示的内容。
You see that NeverCalled()
is never called in the code, don't you? Here's what Compiler Explorer shows when clang 3.8 is selected with
-Os -std=c++11 -Wall
发出的代码是:
NeverCalled():
retq
main:
movl $7, %eax
retq
就像 NeverCalled()
实际上是在 DoSmth()
之前调用的,并将 DoSmth
函数指针设置为 Return7()
函数。
as if NeverCalled()
was actually called before DoSmth()
and set the DoSmth
function pointer to Return7()
function.
如果从 NeverCalled()$ c内部删除了函数指针分配$ c>如下所示:
void NeverCalled() {}
然后发出的代码是这样的:
then code being emitted is this:
NeverCalled():
retq
main:
ud2
后者相当预期。编译器知道函数指针肯定为空,并且使用空函数指针调用函数是未定义的行为。
The latter is quite expected. The compiler knows that function pointer is surely null and calling function using a null function pointer is undefined behavior.
以前的代码并不是真正期望的。编译器决定以某种方式决定调用 Return7()
,尽管它没有在任何地方直接调用,并且函数指针分配在未调用的函数内部。
The former code is not really expected. Somehow the compiler decided to have Return7()
called although it's not directly called anywhere and function pointer assignment is inside function that is not called.
是的,我知道C ++ Standard允许编译器面对未定义行为的代码。
Yes, I know the compiler facing code with undefined behavior is allowed to do this by C++ Standard. Just how does it do this?
铛如何发出此特定机器代码?
How does clang happen to emit this specific machine code?
推荐答案
NeverCalled
是用词不当。可能会调用任何全局函数(例如,通过不同翻译单元中的全局对象的构造函数)。
NeverCalled
is a misnomer. Any global function is potentially called (by a constructor of a global object in a different translation unit, for example).
顺便说一下,这是该TU唯一可能的方法被并入没有UB的程序中。在这种情况下, main
返回7。
Incidentally, this is the only way this TU can possibly be incorporated in a program that doesn't have UB. In this case, main
returns 7.
使 NeverCalled
静态,并且 main
将编译为空代码。
Make NeverCalled
static, and main
will compile to empty code.
这篇关于clang如何将具有未定义行为的代码编译为该机器代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!