Can a C++;编译器在处理指针时优化代码? 这两个问题作为背景(和),我对C++编译器在处理指针时能执行多少优化感到好奇?更具体地说,我感兴趣的是,当编译器优化掉可能检测到永远不会运行的代码时,它有多聪明

Can a C++;编译器在处理指针时优化代码? 这两个问题作为背景(和),我对C++编译器在处理指针时能执行多少优化感到好奇?更具体地说,我感兴趣的是,当编译器优化掉可能检测到永远不会运行的代码时,它有多聪明,c++,optimization,pointers,C++,Optimization,Pointers,(有些人可能会指出,这可能是一个骗局,但其中的这一部分并没有得到完全回答。因此,我决定开始一个新问题,只涉及这一问题。) (我不是C++专家,所以我可能在下面的陈述中错了,但无论如何我会给它一个答案)。C++编译器可以优化代码的部分,它将识别永远不会执行或永不退出(如循环)。以下是一个例子: void test() { bool escape = false; while ( !escape ); // Will never be exited // Do some

(有些人可能会指出,这可能是一个骗局,但其中的这一部分并没有得到完全回答。因此,我决定开始一个新问题,只涉及这一问题。)

(我不是C++专家,所以我可能在下面的陈述中错了,但无论如何我会给它一个答案)。C++编译器可以优化代码的部分,它将识别永远不会执行或永不退出(如循环)。以下是一个例子:


void test() {
    bool escape = false;

    while ( !escape ); // Will never be exited

    // Do something useful after having escaped
}
编译器很可能认识到循环永远不会退出,因为代码永远不会更改
escape
的值,从而退出循环。这使得循环变得无用

现在,如果我们将变量更改为指针,编译器还会优化循环吗?假设代码看起来是这样的:


void test( bool* escape ) {
    while ( *escape ); // Will this be executed?

    // Do something useful after having escaped
}
我怀疑编译器会删除循环,否则关键字
volatile
将是多余的,是吗?。但是,在使用线程时,在实际修改的地方,但在函数之外,甚至可能完全超出C++文件,编译器会不会删除循环?如果
escape
指向的变量是全局变量,还是另一个函数中的局部变量,会有区别吗?编译器可以进行此检测吗?在中,有人说如果在循环内调用库函数,编译器将不会优化循环。当使用库函数时,哪些机制会阻止这种优化?

在第一种情况下(
而(!escape);
)编译器会将其视为
标签:转到标签
并省略它后面的所有内容(可能会给您一个警告)

在第二种情况下(
while(*escape);
),编译器无法知道*escape在运行时是真是假,因此它必须执行编译和循环。但是请注意,它只需从*escape读取一次值,即它可以将其视为:

 bool b = *escape;
 label:   if (b) goto label;

<>代码> Value将迫使它每次通过循环读取“*逃逸”值。

< P>记住C++编译器不知道或给出两个线程的大便。你只有易变性。任何编译器进行优化,破坏多线程代码,但在单线程上运行良好,这是完全合法的。当讨论编译器优化时,不要使用线程,它只是不在图片中

现在,图书馆的功能。当然,这些函数中的任何一个都可以随时更改您的函数*escape,因为编译器无法知道它们是如何工作的。如果将函数作为回调传递,则尤其如此。但是,如果您有一个包含源代码的库,编译器可能会深入研究并发现*escape在其中从未更改


当然,如果循环是空的,它几乎肯定会让你的程序挂起,除非它能在启动时确定条件不是真的。删除一个空的无限循环不是编译器的工作,而是程序员的大脑细胞的工作。

像这样的问题的一般问题是,它们通常包含一个非常不现实的代码片段。“编译器将做什么”的问题需要真正的代码。因为编译器是为编译真实代码而设计和优化的。大多数编译器将完全消除函数和函数调用,因为代码没有副作用。给我们留下了一个没有有用答案的问题


但是,当然,您倾向于使用volatile关键字。你可以在网上找到很多线程,谈论为什么volatile不适合多线程应用程序。

编译器可以做什么和真正的编译器做什么是不同的

本标准在“1.9程序执行”中对此进行了说明。该标准描述了一种抽象机器,要求实现具有相同的“可观察行为”。(这是脚注中记录的“似乎”规则。)

从1.9(6):“抽象机器的可观察行为是它对
volatile
数据的读写序列,以及对库I/O函数的调用。”这意味着,如果您可以证明对函数的修改将导致该函数中或调用后两者都不会发生更改,则修改是合法的


从技术上讲,这意味着如果你编写的函数将永远运行,测试(比如)哥德巴赫的猜想,即所有大于2的偶数都是两个素数的和,并且只有在找到一个不大于2的素数时才停止,那么一个足够巧妙的编译器可以替代输出语句或无限循环,这取决于猜测是假的还是真的(或者在戈德尔意义上是不可证明的)。在实践中,编译器要比最好的数学家拥有更好的定理证明程序还需要一段时间。

是的,有些编译器比其他编译器更聪明。您的第一个示例是一个体面的编译器,无论是否优化,它都会看到它什么也不做,它可能会也可能不会为它生成代码,它可能会也可能不会警告您代码什么都不做

我见过一个编译器,它优化了在一个循环中调用的不同函数中的许多代码行。实际上,我正在尝试进行编译器比较,在循环中重复调用lfsr随机化器(循环运行了硬编码的次数)。一个编译器忠实地编译(并优化)代码,执行每个功能步骤,另一个编译器知道我在做什么,并且生成的汇编程序相当于ldr r0,#0x12345,其中0x12345是答案 ldr r0,[r1] compare: cmp r0,#0 bne compare void test( bool* escape ) { while ( *escape ); } pretest() { bool escape = false; test(&escape); }