1. constexpr이란?
constexpr은 C++11에서 도입된 키워드로, 컴파일 타임에 상수를 만들어 준다고 한다.
const라는 키워드도 상수를 만들 수 있지만, constexpr은 변수 뿐만 아니라 함수, 클래스 생성자에도 적용이 가능하다!
또한, const 키워드는 컴파일 상수 / 런타임 상수 2가지로 작동 가능하지만 constexpr은 컴파일 상수로만 기능한다.
2. constexpr 변수
#include <iostream>
int main(){
int n = 10;
const int constN1 = 100; // OK, initialized at compile-time
const int constN2 = n; // OK, intialized at run-time
constexpr int constExprN1 = 100; // OK, initialized at compile-time
//constexpr int constExprN2 = n; // Error, initialized at run-time
return 0;
}
3. constexpr 함수
constexpr 함수는 함수의 반환 값을 컴파일 타임에 계산할 수 있다는 특징이 있다.
constexpr 함수에는 다음과 같은 규칙이 적용된다.
- constexpr 함수는 리터럴 형식만 사용하고 반환해야 한다.
- constexpr 함수는 재귀적일 수 있다.
- (C++20 이전) constexpr 함수는 가상일 수 없으며, 바깥쪽 클래스에 가상 기본 클래스가 있는 경우 생성자는 constexpr로 정의될 수 없다.
- (C++20 이상) constexpr 함수가 가상일 수 있다.
- 본문은 = default 또는 = delete로 정의할 수 있다.
- 본문에는 goto 문이나 try 블록이 포함될 수 없다.
- ...
#include <iostream>
constexpr int fact(int n){
if(n<0) return 0;
if(n==0) return 1;
return n * fact(n-1);
}
int main(){
constexpr int n = fact(5);
}
근데 함수의 반환 값이 런타임에 계산되는 것과 컴파일 타임에 계산되는 것, 둘의 차이가 어떤 것인지 궁금했다.
위 블로그 내용에 따르면, 어셈블리어 코드로 확인했을 때 확연히 차이나는 것을 볼 수가 있었다.
실제 위의 코드를 https://godbolt.org/에서 확인해본 결과, 아래와 같이 차이가 났었다.
// const 키워드 사용
// CPP
#include <iostream>
const int fact(int n){
if(n<0) return 0;
if(n==0) return 1;
return n * fact(n-1);
}
int main(){
const int n = fact(5);
}
// Assembly
fact(int):
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], edi
cmp DWORD PTR [rbp-4], 0
jns .L2
mov eax, 0
jmp .L3
.L2:
cmp DWORD PTR [rbp-4], 0
jne .L4
mov eax, 1
jmp .L3
.L4:
mov eax, DWORD PTR [rbp-4]
sub eax, 1
mov edi, eax
call fact(int)
imul eax, DWORD PTR [rbp-4]
.L3:
leave
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov edi, 5
call fact(int)
mov DWORD PTR [rbp-4], eax
mov eax, 0
leave
ret
// constexpr 키워드 사용
// CPP
#include <iostream>
constexpr int fact(int n){
if(n<0) return 0;
if(n==0) return 1;
return n * fact(n-1);
}
int main(){
constexpr int n = fact(5);
}
// Assembly
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 120
mov eax, 0
pop rbp
ret
단순히 확인해봐도 큰 차이가 보인다.
컴파일 시간이 오래 걸린다는 단점이 있지만, 런타임에 계산하는 것보다는 훨 나아보이는 방식이다.
결과 값이 수시로 바뀌는 경우가 아니라면 constexpr를 사용하는 것이 성능 상의 큰 도움이 될 것 같다.
References
'언어 > C,C++' 카테고리의 다른 글
[Win32] Visual Studio Win32 LNK2019 오류 해결 (0) | 2023.12.28 |
---|---|
C language Chapter 7. 배열 (0) | 2022.10.09 |
C Language Chapter 6. 반복문 (0) | 2020.08.03 |
C language Chapter 5. C언어의 조건문(+switch문) (0) | 2020.04.17 |
C language Chapter 4. C언어의 입출력 (0) | 2020.03.17 |