4 분 소요

(C++11~) alignas(), alignof()

기존에는 #pragma pack을 이용하여 비표준 방식으로 메모리 정렬을 했는데요(개체 크기와 메모리 정렬 참고),

C++11 부터는 alignas() 와 alignof() 로 이를 표준화하였습니다.

항목 내용
alignof() (C++11~) 주어진 타입의 메모리 정렬 크기를 구합니다.
alignas() (C++11~) 주어진 값으로 메모리 정렬을 합니다. 단, 2, 4, 8, 16… 단위로 정렬하며, 내부 멤버중 제일 큰 값보다 작으면 무시합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 4byte 단위로 정렬합니다.
class alignas(alignof(int)) A_11 {
    char m_A;
    int m_B;
};

// 2, 4, 8, 16... 단위로 정렬하며, 내부 멤버중 제일 큰값보다 커야 합니다.
class alignas(8) B_11 {
    char m_A[13];
    int m_B; 
};

// 2는 내부 멤버중 제일 큰 값인 int 보다 적은값이므로 무시되고 alignof(int) 크기로 정렬됩니다.
class alignas(2) C_11 {
    char m_A[13];
    int m_B; 
};

// 4byte 단위로 멤버 변수가 할당 되므로 char(1) + int(4) = 5 이므로 4 * 2 개 영역에 할당됨
EXPECT_TRUE(alignof(A_11) == 4 && sizeof(A_11) == 4 * 2);

// 8byte 단위로 멤버 변수가 할당 되므로 13 + int(4) = 17 이므로 8 * 3 개 영역에 할당됨
EXPECT_TRUE(alignof(B_11) == 8 && sizeof(B_11) == 8 * 3); 

// 4byte 단위로 멤버 변수가 할당 되므로 13 + int(4) = 17 이므로 4 * 5 개 영역에 할당됨
EXPECT_TRUE(alignof(C_11) == 4 && sizeof(C_11) == 4 * 5); 

(C++11~)가변 매크로

가변 매크로는 C99 에 도입되었으며, C와의 호환성을 위해 C++11에 추가되었습니다.

가변 인자를 사용하는 함수를 매크로 함수로 호출할 때 사용합니다.

다음 코드에서처럼 매크로 함수 정의시에 ...을 사용하고, __VA_ARGS__를 이용하여 전달할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define MY_SUM_11(count, ...) T::Sum(count, __VA_ARGS__)

class T {
public:
    static int Sum(int count, ...) {
        int result{0};
        std::va_list paramList; // 가변 인자
        va_start(paramList, count); // 가변 인자 처리 시작
        for (int i{0}; i < count; ++i) {
            result += va_arg(paramList, int); // 가변 인자 추출
        }
        va_end(paramList); // 가변 인자 처리 끝
        return result;       
    }
};
// 가변 인자에 인수가 있는 경우
EXPECT_TRUE(T::Sum(3, 1, 2, 3) == 1 + 2 + 3);
EXPECT_TRUE(MY_SUM_11(3, 1, 2, 3) == 1 + 2 + 3);

하지만, 인수가 없는 경우에는 T::Sum(count, )로 치환되어 컴파일 오류가 납니다.

1
2
3
// 가변 인자에 인수가 없는 경우
EXPECT_TRUE(T::Sum(0) == 0);
EXPECT_TRUE(MY_SUM_11(0) == 0); // (X) 컴파일 오류. T::Sum(count, ) 로 치환됩니다.

이러한 문제 때문에 ##__VA_ARGS__ 가 제공되며, 앞의 ,를 없애줍니다.

1
2
3
4
5
6
7
#define MY_SUM(count, ...) T::Sum(count, __VA_ARGS__)
#define MY_SUM2_11(count, ...) T::Sum(count, ##__VA_ARGS__)

// 가변 인자에 인수가 없는 경우
EXPECT_TRUE(T::Sum(0) == 0);
EXPECT_TRUE(MY_SUM(0) == 0); // (X) 컴파일 오류. T::Sum(count, ) 로 치환됩니다.
EXPECT_TRUE(MY_SUM2_11(0) == 0); // (O)  

(C++11~) 멤버 sizeof() 연산자

멤버의 sizeof()시 동작이 개선되어 개체를 인스턴스화 하지 않더라도 개체 멤버의 크기를 구할 수 있습니다.

1
2
3
4
5
6
7
8
class T {
public:
    int m_X;
};

// (X) C++03 에서는 컴파일 오류
// (O) C++11 부터 허용
EXPECT_TRUE(sizeof(T::m_X) == sizeof(int));

(C++17~) __has_include

파일이 존재하는지 확인하는 전처리기 입니다.

1
2
3
#if __has_include(<optional>)
#  include <optional>
#endif

(C++20~) volatile 일부 deprecate

다음 4가지 경우에 대해 volatile 사용이 deprecate되었습니다.

  • 복합 대입

    1
    2
    3
    4
    5
    6
    7
    8
    
      int a, b;
      volatile int volatile_val;
    
      // 복합 대입 deprecate
      volatile_val = a; // (O)
      b = volatile_val; // (O)
    
      b = volatile_val = a; // (X) volatile_val에 한번 접근하는지 두번 접근하는지 모호
    
  • 산술형 대입 연산, 증감 연산

    1
    2
    3
    4
    5
    
      volatile int volatile_val;
    
      // 산술형 대입 연산자, 증감 연산자 deprecate
      volatile_val = volatile_val + 1; // (O)
      volatile_val += 1; // (X) volatile_val에 한번 접근하는지 두번 접근하는지 모호
    
  • 함수 인자와 리턴값

    1
    2
    3
    
      // 함수 인자와 리턴값 deprecate
      volatile int f(); // (X)
      void g(volatile int); // (X)
    
  • 구조적 바인딩

    1
    2
    3
    4
    5
    6
    7
    
      // 구조적 바인딩 deprecate
      sturct A {
          volatile int x;
          volatile int y;
      };
      A a;
      auto [x_17, y_17]{a}; // (X)    
    

(C++20~) VA_OPT

__VA_OPT__가 추가되어 가변 인자가 있을 경우에는 괄호 안의 값으로 치환하고, 없을 경우에는 그냥 비워둡니다.

1
2
3
4
5
int Sum(int init, int a, int b, int c) {return init + a + b + c;}
int Sum(int init) {return init;}
#define MY_FUNC_20(...) Sum(10 __VA_OPT__(,) __VA_ARGS__) // 가변 인수가 있다면 ,를 넣습니다.
EXPECT_TRUE(MY_FUNC_20(1, 2, 3) == 10 + 1 + 2 + 3); // f(10, 1, 2, 3)가변 인수가 있다면 , 를 넣습니다.
EXPECT_TRUE(MY_FUNC_20() == 10); // f(10)가변 인수가 없다면 ,를 넣지 않습니다.

__has_cpp_attribute() 매크로 함수

C++20 부터는 __has_cpp_attribute() 매크로 함수가 추가되어 C++11부터 추가된 특성(attirbute)이 지원되는지 확인 할 수 있습니다.

테스트할 수 있는 특성(attirbute)https://en.cppreference.com/w/cpp/feature_test를 참고하시기 바랍니다.

1
2
3
4
5
#if __has_cpp_attribute(deprecated)
    std::cout << "Support deprecated" << std::endl; // deprecated를 지원합니다.
#else 
    std::cout << "No Support deprecated" << std::endl;
#endif

언어 지원 테스트

C++20 부터는 언어 지원 테스트 매크로가 추가되어 컴파일러가 C++11부터 추가된 언어 기능을 지원하는지 테스트 할 수 있습니다.

테스트할 수 있는 항목은 https://en.cppreference.com/w/cpp/feature_test를 참고하시기 바랍니다.

1
2
3
4
5
#if __cpp_char8_t
    std::cout << "Support char8_t" << std::endl; // char8_t를 지원합니다.
#else 
    std::cout << "No Support char8_t" << std::endl;
#endif  

(C++20~) STL 지원 테스트 매크로가 추가되어 C++11부터 추가된 STL 기능을 지원하는지 테스트 할 수 있습니다.

태그:

카테고리:

업데이트:

댓글남기기