当涉及到C和C++语言时,编译器是否会优化对常量变量的引用,以便程序自动知道所引用的值,而不必窥视常量变量的内存位置?当涉及到数组时,是否取决于在编译时指向数组的索引值是否为常量?
例如,看一下这段代码:
int main(void) {
1: char tesst[3] = {'1', '3', '7'};
2: char erm = tesst[1];
}
编译器在编译时是否会将第二行“char erm = '3'”更改为其他形式?
当涉及到C和C++语言时,编译器是否会优化对常量变量的引用,以便程序自动知道所引用的值,而不必窥视常量变量的内存位置?当涉及到数组时,是否取决于在编译时指向数组的索引值是否为常量?
例如,看一下这段代码:
int main(void) {
1: char tesst[3] = {'1', '3', '7'};
2: char erm = tesst[1];
}
编译器在编译时是否会将第二行“char erm = '3'”更改为其他形式?
我个人认为,由于这两个变量都没有被使用,所以应该将发布的代码转换为“nothing”,因此可以将其删除。
但是,现代编译器(如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
内部获取值。
这主要取决于优化级别和使用的编译器。
使用最大优化,编译器可能只会用char erm = '3';
替换你的整个代码。GCC -O3就是这样做的。
但这当然也取决于你如何使用该变量。编译器甚至可能不分配变量,而只在变量出现的操作中使用原始数字。
编辑: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上阅读更多关于此的信息。
constexpr
表达式不能保证在编译时被求值。如果程序是良好形式的,那么在编译时求值constexpr
表达式总是可能的,但编译器并不本质上有义务执行该求值。(然而,在使用这种表达式的上下文中可能会创建这样的义务。) - John Bollingerconstexpr
变量不是必须在编译时计算吗? - NathanOliverconstexpr
表达式受到约束,使得可以在编译时评估它们,但据我所知,标准并不坚持编译时评估实际发生。 - John Bollinger
const
只意味着对象的可观察状态不会改变。然而,一个const
对象可能有mutable
的私有字段,在这种情况下,不能使用副本来代替对对象引用的解引用。 - 463035818_is_not_a_number