对于C和C ++语言,编译器是否优化对常量变量的引用,以便程序自动知道所引用的值,而不必查看常量变量的内存位置?说到数组,是否取决于在编译时指向数组的索引值是否为常量?
例如,看看这段代码:
int main(void) {
1: char tesst[3] = {'1', '3', '7'};
2: char erm = tesst[1];
}
编译时编译器是否将第2行“更改”为“char erm ='3'”?
答案 0 :(得分:10)
我个人希望发布的代码变成“无”,因为这两个变量实际上都没有使用,因此可以删除。
但是,现代编译器(gcc,clang,msvc等)应该能够用它的常量值替换对替代的引用[只要编译器可以合理地确定tesst
的内容没有被更改 - 如果你将tesst
传递给一个函数,即使它作为const
引用,并且编译器实际上并不知道函数没有改变它,它会假设它做并加载值。。
使用clang -O1 opts.c -S
:
#include <stdio.h>
int main()
{
char tesst[3] = {'1', '3', '7'};
char erm = tesst[1];
printf("%d\n", erm);
}
产生
...
main:
pushq %rax
.Ltmp0:
movl $.L.str, %edi
movl $51, %esi
xorl %eax, %eax
callq printf
xorl %eax, %eax
popq %rcx
retq
...
所以,与printf("%d\n", '3');
相同。
[我使用的是C而不是C ++,因为如果我使用cout
,那将是大约50行汇编程序,因为所有内容都被内联了]
我希望gcc和msvc进行类似的优化(测试gcc -O1 -S
并且它提供完全相同的代码,除了一些符号名称略有不同)
并说明“如果你调用一个函数它可能不会这样做”:
#include <stdio.h>
extern void blah(const char* x);
int main()
{
char tesst[3] = {'1', '3', '7'};
blah(tesst);
char erm = tesst[1];
printf("%d\n", erm);
}
main: # @main
pushq %rax
movb $55, 6(%rsp)
movw $13105, 4(%rsp) # imm = 0x3331
leaq 4(%rsp), %rdi
callq blah
movsbl 5(%rsp), %esi
movl $.L.str, %edi
xorl %eax, %eax
callq printf
xorl %eax, %eax
popq %rcx
retq
现在,它从tesst
内部获取值。
答案 1 :(得分:7)
它主要取决于优化级别和您使用的编译器。
通过最大程度的优化,编译器确实可能只用char erm = '3';
替换整个代码。无论如何,GCC -O3都会这样做。
但当然这取决于你对该变量的处理方式。编译器甚至可能不会分配变量,而只是在变量发生的操作中使用原始数字。
答案 2 :(得分:3)
取决于编译器版本,使用的优化选项以及许多其他内容。如果你想确保const变量是优化的,如果它们是编译时常量,你可以在c ++中使用类似 constexpr 的东西。与普通的const变量不同,它保证在编译时进行评估。
编辑:constexpr可以在编译时或运行时进行评估。为了保证编译时评估,我们必须在需要常量表达式的地方使用它(例如,作为数组绑定或作为case标签)或使用它来初始化constexpr。所以在这种情况下
constexpr char tesst[3] = {'1','3','7'};
constexpr char erm = tesst[1];
会导致编译时评估。很高兴阅读https://isocpp.org/blog/2013/01/when-does-a-constexpr-function-get-evaluated-at-compile-time-stackoverflow