When it comes to the C and C++ languages, does the compiler optimize references to constant variables so that the program automatically knows what values are being referred to, instead of having to peek at the memory locations of the constant variables? When it comes to arrays, does it depend on whether the index value to point at in the array is a constant at compile time?
当谈到C和C ++语言时,编译器是否优化对常量变量的引用,以便程序自动知道所引用的值,而不必查看常量变量的内存位置?说到数组,是否取决于在编译时指向数组的索引值是否为常量?
For instance, take a look at this code:
例如,看看这段代码:
int main(void) {
1: char tesst[3] = {'1', '3', '7'};
2: char erm = tesst[1];
}
Does the compiler "change" line 2 to "char erm = '3'" at compile time?
编译时编译器是否将第2行“更改”为“char erm ='3'”?
3 个解决方案
#1
7
It mostly depends on the level of optimization and which compiler you are using.
它主要取决于优化级别和您使用的编译器。
With maximum optimizations, the compiler will indeed probably just replace your whole code with char erm = '3';
. GCC -O3 does this anyway.
通过最大程度的优化,编译器确实可能只用char erm ='3'替换整个代码。无论如何,GCC -O3都是这样做的。
But then of course it depends on what you do with that variable. The compiler might not even allocate the variable, but just use the raw number in the operation where the variable occurs.
但当然这取决于你对该变量的处理方式。编译器甚至可能不会分配变量,而只是在发生变量的操作中使用原始数字。
#2
9
I personally would expect the posted code to turn into "nothing", since neither variable is actually used, and thus can be removed.
我个人希望发布的代码变成“无”,因为这两个变量实际上都没有使用,因此可以删除。
But yes, modern compilers (gcc, clang, msvc, etc) should be able to replace that reference to the alternative with it's constant value [as long as the compiler can be reasonably sure that the content of tesst
isn't being changed - if you pass tesst
into a function, even if its as a const
reference, and the compiler doesn't actually know the function is NOT changing that, it will assume that it does and load the value].
但是,现代编译器(gcc,clang,msvc等)应该能够用它的常量值替换对替代的引用[只要编译器可以合理地确定tesst的内容没有被更改 - 如果你将tesst传递给一个函数,即使它作为一个const引用,并且编译器实际上并不知道函数没有改变它,它会假设它执行并加载值]。
Compiling this using clang -O1 opts.c -S
:
使用clang -O1 opts.c -S编译它:
#include <stdio.h>
int main()
{
char tesst[3] = {'1', '3', '7'};
char erm = tesst[1];
printf("%d\n", erm);
}
produces:
...
main:
pushq %rax
.Ltmp0:
movl $.L.str, %edi
movl $51, %esi
xorl %eax, %eax
callq printf
xorl %eax, %eax
popq %rcx
retq
...
So, the same as printf("%d\n", '3');
.
因此,与printf相同(“%d \ n”,“3”);.
[I'm using C rather than C++ because it would be about 50 lines of assembler if I used cout
, as everything gets inlined]
[我正在使用C而不是C ++,因为如果我使用cout,它将是大约50行汇编程序,因为所有内容都被内联]
I expect gcc and msvc to make a similar optimisation (tested gcc -O1 -S
and it gives exactly the same code, aside from some symbol names are subtly different)
我希望gcc和msvc进行类似的优化(测试gcc -O1 -S并且它给出完全相同的代码,除了一些符号名称略有不同)
And to illustrate that "it may not do it if you call a function":
并说明“如果你调用一个函数它可能不会这样做”:
#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
Now, it fetches the value from inside tesst
.
现在,它从tesst内部获取值。
#3
3
Depends on the compiler version, optimization options used and many other things. If you want to make sure that the const variables are optimized and if they are compile time constants you can use something like constexpr in c++. It is guaranteed to be evaluated at compile time unlike normal const variables.
取决于编译器版本,使用的优化选项和许多其他事项。如果你想确保const变量是优化的,如果它们是编译时常量,你可以在c ++中使用constexpr之类的东西。与普通的const变量不同,它保证在编译时进行评估。
Edit: constexpr may be evaluated at compile time or runtime. To guarantee compile-time evaluation, we must either use it where a constant expression is required (e.g., as an array bound or as a case label) or use it to initialize a constexpr. so in this case
编辑:constexpr可以在编译时或运行时进行评估。为了保证编译时评估,我们必须在需要常量表达式的地方使用它(例如,作为数组绑定或作为案例标签)或使用它来初始化constexpr。所以在这种情况下
constexpr char tesst[3] = {'1','3','7'};
constexpr char erm = tesst[1];
would lead to compile time evaluation. Nice read at https://isocpp.org/blog/2013/01/when-does-a-constexpr-function-get-evaluated-at-compile-time-*
会导致编译时评估。好的阅读https://isocpp.org/blog/2013/01/when-does-a-constexpr-function-get-evaluated-at-compile-time-*
#1
7
It mostly depends on the level of optimization and which compiler you are using.
它主要取决于优化级别和您使用的编译器。
With maximum optimizations, the compiler will indeed probably just replace your whole code with char erm = '3';
. GCC -O3 does this anyway.
通过最大程度的优化,编译器确实可能只用char erm ='3'替换整个代码。无论如何,GCC -O3都是这样做的。
But then of course it depends on what you do with that variable. The compiler might not even allocate the variable, but just use the raw number in the operation where the variable occurs.
但当然这取决于你对该变量的处理方式。编译器甚至可能不会分配变量,而只是在发生变量的操作中使用原始数字。
#2
9
I personally would expect the posted code to turn into "nothing", since neither variable is actually used, and thus can be removed.
我个人希望发布的代码变成“无”,因为这两个变量实际上都没有使用,因此可以删除。
But yes, modern compilers (gcc, clang, msvc, etc) should be able to replace that reference to the alternative with it's constant value [as long as the compiler can be reasonably sure that the content of tesst
isn't being changed - if you pass tesst
into a function, even if its as a const
reference, and the compiler doesn't actually know the function is NOT changing that, it will assume that it does and load the value].
但是,现代编译器(gcc,clang,msvc等)应该能够用它的常量值替换对替代的引用[只要编译器可以合理地确定tesst的内容没有被更改 - 如果你将tesst传递给一个函数,即使它作为一个const引用,并且编译器实际上并不知道函数没有改变它,它会假设它执行并加载值]。
Compiling this using clang -O1 opts.c -S
:
使用clang -O1 opts.c -S编译它:
#include <stdio.h>
int main()
{
char tesst[3] = {'1', '3', '7'};
char erm = tesst[1];
printf("%d\n", erm);
}
produces:
...
main:
pushq %rax
.Ltmp0:
movl $.L.str, %edi
movl $51, %esi
xorl %eax, %eax
callq printf
xorl %eax, %eax
popq %rcx
retq
...
So, the same as printf("%d\n", '3');
.
因此,与printf相同(“%d \ n”,“3”);.
[I'm using C rather than C++ because it would be about 50 lines of assembler if I used cout
, as everything gets inlined]
[我正在使用C而不是C ++,因为如果我使用cout,它将是大约50行汇编程序,因为所有内容都被内联]
I expect gcc and msvc to make a similar optimisation (tested gcc -O1 -S
and it gives exactly the same code, aside from some symbol names are subtly different)
我希望gcc和msvc进行类似的优化(测试gcc -O1 -S并且它给出完全相同的代码,除了一些符号名称略有不同)
And to illustrate that "it may not do it if you call a function":
并说明“如果你调用一个函数它可能不会这样做”:
#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
Now, it fetches the value from inside tesst
.
现在,它从tesst内部获取值。
#3
3
Depends on the compiler version, optimization options used and many other things. If you want to make sure that the const variables are optimized and if they are compile time constants you can use something like constexpr in c++. It is guaranteed to be evaluated at compile time unlike normal const variables.
取决于编译器版本,使用的优化选项和许多其他事项。如果你想确保const变量是优化的,如果它们是编译时常量,你可以在c ++中使用constexpr之类的东西。与普通的const变量不同,它保证在编译时进行评估。
Edit: constexpr may be evaluated at compile time or runtime. To guarantee compile-time evaluation, we must either use it where a constant expression is required (e.g., as an array bound or as a case label) or use it to initialize a constexpr. so in this case
编辑:constexpr可以在编译时或运行时进行评估。为了保证编译时评估,我们必须在需要常量表达式的地方使用它(例如,作为数组绑定或作为案例标签)或使用它来初始化constexpr。所以在这种情况下
constexpr char tesst[3] = {'1','3','7'};
constexpr char erm = tesst[1];
would lead to compile time evaluation. Nice read at https://isocpp.org/blog/2013/01/when-does-a-constexpr-function-get-evaluated-at-compile-time-*
会导致编译时评估。好的阅读https://isocpp.org/blog/2013/01/when-does-a-constexpr-function-get-evaluated-at-compile-time-*