Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么有些编译器优化if(a>;0)而不是if(*(&;a)>;0)?_C_Optimization_Compiler Construction_Rvds - Fatal编程技术网

C 为什么有些编译器优化if(a>;0)而不是if(*(&;a)>;0)?

C 为什么有些编译器优化if(a>;0)而不是if(*(&;a)>;0)?,c,optimization,compiler-construction,rvds,C,Optimization,Compiler Construction,Rvds,假设我在全球范围内声明: const int a =0x93191; 在主函数中,我有以下条件: if(a>0) do_something 我注意到的一件尴尬的事情是RVDS编译器将删除if语句,并且对象文件中没有分支/jmp 但是如果我写: if(*(&a)>0) do_something if(cmp和分支)将位于编译的对象文件中 相比之下,GCCdo使用(-O1或-O2或-O3)优化这两种方法: 我使用的RVDS的编译器版本中可能存在一些错误。编

假设我在全球范围内声明:

const int a =0x93191;
在主函数中,我有以下条件:

if(a>0)
    do_something
我注意到的一件尴尬的事情是
RVDS
编译器将删除
if
语句,并且对象文件中没有分支/jmp

但是如果我写:

if(*(&a)>0)
    do_something
if(
cmp
分支
)将位于编译的对象文件中


相比之下,
GCC
do使用(
-O1
-O2
-O3
)优化这两种方法:


我使用的RVDS的编译器版本中可能存在一些错误。

编译器将要经历的复杂程度并不是无限的,它会发现“这是我能够计算出实际值的东西吗?”。如果您编写一个足够复杂的语句,编译器将简单地说“我不知道该值是什么,我将生成代码来计算它”

这对于编译器来说是完全可能的,因为它不会改变。但也有可能一些编译器在这个过程中“放弃”——这也可能取决于在编译链中的什么位置进行此分析

这可能是“仿佛”规则的一个相当典型的例子——编译器可以执行任何优化,生成“仿佛”执行的结果


话虽如此,这应该是相当琐碎的(根据注释,编译器应该使用与
a
相同的
*(&a)
),因此它没有摆脱比较似乎很奇怪

优化是编译器的实现细节。实现它们需要时间和精力,编译器编写人员通常关注语言的常见用途(即,优化非常罕见的代码的投资回报几乎为零)

也就是说,这两段代码有一个重要的区别,在第一种情况下,
a
不使用odr,只用作右值,这意味着它可以作为编译时常量处理。也就是说,当直接使用
a
时(没有地址,没有绑定到它的引用),编译器会立即替换中的值。编译器必须在不访问变量的情况下知道该值,因为它可以在需要常量表达式(即定义数组大小)的上下文中使用


在第二种情况下,
a
使用odr,获取地址并读取该位置的值。在将结果传递给优化器之前,编译器必须生成执行这些步骤的代码。优化器反过来可以检测到它是一个常量,并用该值替换整个操作,但这比以前编译器本身填充值的情况要复杂一些。

什么编译器和什么编译器选项?@0x90
armvct
我以前没听说过这个编译器?你能发布链接以便我们更好地模拟它们吗?GCC 4.5.3在
-O1
和更高版本中优化了分支。为什么你不发布ARM程序集转储呢?RVDS的输出在哪里?除了RVDS这个词外,这似乎与ARM无关。另一个模块可以获取
常量的地址并对其进行更改。在C++中,没有全局代码> const < />代码,但是在C中有。也就是说,编译器不必为变量分配空间。例如,
const
硬件寄存器可能意味着它对软件是只读的;使用
extern const
时,该行为更有意义。一些人可能通过阅读标准得出结论,编译器应该同样对待这些问题。由于编译器需要针对所有这些情况进行优化,因此信息
(*(&a))
可能无法进入优化器阶段,特别是当您给出变量全局范围时。毫无疑问,这是编译器无法识别优化机会,但这并不像在编译器中跨越某个复杂度阈值那么简单
*(&a)
不仅是一个非常简单的表达式,而且在C标准的脚注中明确指出它等同于
a
(1999年标准中的注释83,1999年TC2草案中的注释84,2011年的草案n1124和102)。我们知道,给定
a
的可见值,该编译器会优化
a>0
。因此,它未能优化
*(&a)>0
这一事实表明它错过了C语义的一个清晰明确的方面!我对这篇文章投了反对票,因为还有别的事情发生。没有合理的编译器会退出。@ EricPostpischil:在C++中,它不是完全相同的。积分常数在C和C++中略有不同。在C++中,<代码> a < /> >不构成ODR使用常量<代码> A<代码>,而<代码> */A<代码>是ODR使用的。虽然在示例代码中,这并不重要(符号已定义),但对于静态成员来说可能很重要。@Mikhail一个合理的编译器可能会放弃,因为变量不是静态的。
#include <stdio.h>
const a = 3333;

int main()
{
    if (a >333)
        printf("first\n");

return 0;
}
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000100000f10 <main+0>:    push   %rbp
0x0000000100000f11 <main+1>:    mov    %rsp,%rbp
0x0000000100000f14 <main+4>:    lea    0x3d(%rip),%rdi        # 0x100000f58
0x0000000100000f1b <main+11>:   callq  0x100000f2a <dyld_stub_puts>
0x0000000100000f20 <main+16>:   xor    %eax,%eax
0x0000000100000f22 <main+18>:   pop    %rbp
0x0000000100000f23 <main+19>:   retq   
End of assembler dump.
#include <stdio.h>
const a = 3333;

int main()
{
        if (*(&a) >333)
                printf("first\n");

return 0;
}
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000100000f10 <main+0>:    push   %rbp
0x0000000100000f11 <main+1>:    mov    %rsp,%rbp
0x0000000100000f14 <main+4>:    lea    0x3d(%rip),%rdi        # 0x100000f58
0x0000000100000f1b <main+11>:   callq  0x100000f2a <dyld_stub_puts>
0x0000000100000f20 <main+16>:   xor    %eax,%eax
0x0000000100000f22 <main+18>:   pop    %rbp
0x0000000100000f23 <main+19>:   retq   
End of assembler dump.
#include <stdio.h>
volatile const a = 3333;

int main()
{
    if (a >333)
        printf("first\n");

return 0;
}

(gdb) disassemble main
Dump of assembler code for function main:
0x0000000100000f10 <main+0>:    push   %rbp
0x0000000100000f11 <main+1>:    mov    %rsp,%rbp
0x0000000100000f14 <main+4>:    cmpl   $0x14e,0x12a(%rip)        # 0x100001048 <a>
0x0000000100000f1e <main+14>:   jl     0x100000f2c <main+28>
0x0000000100000f20 <main+16>:   lea    0x39(%rip),%rdi        # 0x100000f60
0x0000000100000f27 <main+23>:   callq  0x100000f36 <dyld_stub_puts>
0x0000000100000f2c <main+28>:   xor    %eax,%eax
0x0000000100000f2e <main+30>:   pop    %rbp
0x0000000100000f2f <main+31>:   retq   
End of assembler dump.