Constexpr变量评估
Constexpr variable evaluation
这是我的代码,我需要说明发生了什么:
constexpr int funct(int x){
return x + 1;
}
int main(){
int x = funct(10);
return 0;
}
constexpr
's允许编译时计算,根据我上面的代码,由于funct
被声明为constexpr
,所以允许进行编译时计算如果参数是常量或 constexpr 本身。
我比较困惑的部分就在这部分,int x
。既然没有声明为constexpr
,是不是意味着int x
会在运行时获取值?这是否意味着将其声明为 constexpr int x
将意味着 int x 将在编译时获得与 int x
不同的值?
这在很多方面取决于所讨论的编译器。可能发生什么样的优化等。但是,constexpr 本身并不启用编译时计算。
取此代码:
#include <cstdio>
constexpr int test(int in)
{
return in + 25;
}
int main(int argc, char* argv[])
{
printf("Test: %u\n", test(5));
printf("Two: %u\n", test(10));
}
在我的 x86_64 Gentoo box 上的 GCC 4.8.4 下,它实际上仍然对所谓的编译时间 "test" 进行了这两项调用。我使用的线路是
g++ -std=c++11 -Wall -g -c main.cpp -o obj/Debug/main.o
g++ -o bin/Debug/TestProject obj/Debug/main.o
所以在上面的代码中,生成以下机器代码:
0x40061c mov edi,0x5
0x400621 call 0x400659 <test(int)>
0x400626 mov esi,eax
0x400628 mov edi,0x4006f4
0x40062d mov eax,0x0
0x400632 call 0x4004f0 <printf@plt>
0x400637 mov edi,0xa
0x40063c call 0x400659 <test(int)>
0x400641 mov esi,eax
0x400643 mov edi,0x4006fd
0x400648 mov eax,0x0
0x40064d call 0x4004f0 <printf@plt>
"test" 的 asm 块是:
0x400659 push rbp
0x40065a mov rbp,rsp
0x40065d mov DWORD PTR [rbp-0x4],edi
0x400660 mov eax,DWORD PTR [rbp-0x4]
0x400663 add eax,0x19
0x400666 pop rbp
0x400667 ret
因此,正如您在那种情况下看到的那样,它似乎对 GCC 如何生成该代码几乎没有影响。即使你这样做,你仍然会得到运行时计算:
int value = test(30);
printf("Value: %u\n", value);
产生这个的地方(由于添加了更多代码,测试地址略有变化):
0x40061c mov edi,0x1e
0x400621 call 0x40067a <test(int)>
0x400626 mov DWORD PTR [rbp-0x4],eax
0x400629 mov eax,DWORD PTR [rbp-0x4]
0x40062c mov esi,eax
0x40062e mov edi,0x400714
0x400633 mov eax,0x0
0x400638 call 0x4004f0 <printf@plt>
但是,如果您将值 本身 声明为 constexpr,它确实会产生预期的结果:
constexpr int value = test(30);
printf("Value: %u\n", value);
关联代码为:
0x400623 mov esi,0x37
0x400628 mov edi,0x400714
0x40062d mov eax,0x0
0x400632 call 0x4004f0 <printf@plt>
所以基本上,如果您只是在方法声明前加上 constexpr,则不能保证编译时计算。您还需要将变量声明为 constexpr 并分配给它。进行这样的声明实际上 需要 编译器静态评估结果。如果您尝试这样做并且 "test" 未声明为 constexpr,GCC 实际上会对您大喊大叫:
main.cpp|10|error: call to non-constexpr function ‘int test(int)’|
这是我的代码,我需要说明发生了什么:
constexpr int funct(int x){
return x + 1;
}
int main(){
int x = funct(10);
return 0;
}
constexpr
's允许编译时计算,根据我上面的代码,由于funct
被声明为constexpr
,所以允许进行编译时计算如果参数是常量或 constexpr 本身。
我比较困惑的部分就在这部分,int x
。既然没有声明为constexpr
,是不是意味着int x
会在运行时获取值?这是否意味着将其声明为 constexpr int x
将意味着 int x 将在编译时获得与 int x
不同的值?
这在很多方面取决于所讨论的编译器。可能发生什么样的优化等。但是,constexpr 本身并不启用编译时计算。
取此代码:
#include <cstdio>
constexpr int test(int in)
{
return in + 25;
}
int main(int argc, char* argv[])
{
printf("Test: %u\n", test(5));
printf("Two: %u\n", test(10));
}
在我的 x86_64 Gentoo box 上的 GCC 4.8.4 下,它实际上仍然对所谓的编译时间 "test" 进行了这两项调用。我使用的线路是
g++ -std=c++11 -Wall -g -c main.cpp -o obj/Debug/main.o
g++ -o bin/Debug/TestProject obj/Debug/main.o
所以在上面的代码中,生成以下机器代码:
0x40061c mov edi,0x5
0x400621 call 0x400659 <test(int)>
0x400626 mov esi,eax
0x400628 mov edi,0x4006f4
0x40062d mov eax,0x0
0x400632 call 0x4004f0 <printf@plt>
0x400637 mov edi,0xa
0x40063c call 0x400659 <test(int)>
0x400641 mov esi,eax
0x400643 mov edi,0x4006fd
0x400648 mov eax,0x0
0x40064d call 0x4004f0 <printf@plt>
"test" 的 asm 块是:
0x400659 push rbp
0x40065a mov rbp,rsp
0x40065d mov DWORD PTR [rbp-0x4],edi
0x400660 mov eax,DWORD PTR [rbp-0x4]
0x400663 add eax,0x19
0x400666 pop rbp
0x400667 ret
因此,正如您在那种情况下看到的那样,它似乎对 GCC 如何生成该代码几乎没有影响。即使你这样做,你仍然会得到运行时计算:
int value = test(30);
printf("Value: %u\n", value);
产生这个的地方(由于添加了更多代码,测试地址略有变化):
0x40061c mov edi,0x1e
0x400621 call 0x40067a <test(int)>
0x400626 mov DWORD PTR [rbp-0x4],eax
0x400629 mov eax,DWORD PTR [rbp-0x4]
0x40062c mov esi,eax
0x40062e mov edi,0x400714
0x400633 mov eax,0x0
0x400638 call 0x4004f0 <printf@plt>
但是,如果您将值 本身 声明为 constexpr,它确实会产生预期的结果:
constexpr int value = test(30);
printf("Value: %u\n", value);
关联代码为:
0x400623 mov esi,0x37
0x400628 mov edi,0x400714
0x40062d mov eax,0x0
0x400632 call 0x4004f0 <printf@plt>
所以基本上,如果您只是在方法声明前加上 constexpr,则不能保证编译时计算。您还需要将变量声明为 constexpr 并分配给它。进行这样的声明实际上 需要 编译器静态评估结果。如果您尝试这样做并且 "test" 未声明为 constexpr,GCC 实际上会对您大喊大叫:
main.cpp|10|error: call to non-constexpr function ‘int test(int)’|