상세 컨텐츠

본문 제목

PRE00-C. 함수형의 매크로보다는 인라인이나 정적 함수를 사용하라.

개발 환경/CERT - 취약점

by cepiloth 2021. 6. 1. 12:37

본문

728x90
반응형

 매크로는 사용법이 함수와 비슷하지만 문법은 다르기 때문에 위험하다. C99에서는 C 프로그래밍 언어에 인라인 함수를 도입했는데, 인라인 함수와 매크로를 모두 사용할 수 있는 경우라면 인라인 함수를 사용하는 편이 좋다. 인라인 함수를 사용하면 우리가 알고 있는 함수 호출 프로시저가 인라인으로 치환되기 때문에 함수 호출이 빨라진다.

 논란의 여지는 있지만 함수를 인라인으로 만들지 여부는 프로그래머의 입력에 따르지 않고 컴파일러가 로우 레벨 수준의 최적화에서 직접 결정해야 한다. 인라인 함수를 사용하고자 할 때 고려사항은 아래와 같다.

(a) 컴파일러가 얼마만큼 잘 지원하는지?

(b) 시스템의 성능에 어떤 영향을 미치게 될지?

(c) 이식성이 있는지를 생각해봐야 한다.

 

부적절한 코드 예

아래 코드는 CUBE() 매크로에 부수 효과가 발생하는 표현식을 전달하면 정의되지 않은 행동을 유발할 수 있다.

#define CUBE(X) ((X) * (X) * (X))
/* ... */

int i = 2;
int a = 81 / CUBE(++i);

// 이 매크로는 아래와 같치 치환 되어
int a = 81 / ((++i) * (++i) * (++i));

정의되지 않은 결과를 낸다.

 

해결 방법

매크로 정의를 인라인 함수로 바꾸면 부수 효과는 함수가 호출되기 전에 한 번만 발생한다.

inline int cube(int i) {
	return i * i * i;
}

/* ... */

int i = 2;
int a = 81 cube(++i);

 

예외

PRE00-EX1 : 한 스코프 내부에 있는 자동 변수만 접근하는 코드가 반복되어 이를 지역 함수로 만들려고 하는데 인라인 함수로 구현할 수 없는 경우 매크로를 사용할 수 있다.

PRE00-EX2 : 인라인 함수로는 구현할 수 없는 형태의 연산을 만들기 위해 매크로를 사용할 수 있다. 아래처럼 선택자의 값에 따라 둘 중 하나의 표현식만 계산되는 경우다.

#define SELECT(s, v1, v2) ((s) ? (v1) : (v2))

 

PRE00-EX03 : 컴파일할 때 매크로에서 상수가 되는 표현식이 인라인 함수에서는 상수가 되지 않으므로 이에 한해 매크로로 나타낼 수 있다.

#define ADD_M(a, b) ((a) + (b))
static inline add_f(int a, int b) {
	return a + b;
}

이 코드에서 ADD_M(3, 4)와 같이 사용하면 컴파일 시 상수(7)가 되나, 인라인 함수 add_f(3, 4) 처럼 사용하면 표현식(3+4)이 된다.

 

PRE00-EX04 : C에는 C++의 템플릿 같은 메커니즘이 없음으로, 매크로를 사용해 템플릿 함수 같은 일반적인 타입을 처리하는 함수를 구현할 수 있다. "메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라." 일반적인 타입을 처리하는 매크로를 사용할 수도 있는데, 예를 들면 같은 타입의 두 변수가 주어졌을 때 어떤 타입이든지 두 변수의 값을 스왑 하는 경우가 있다.

PRE00-EX05 : 함수가 값에 의한 호출인 반면 매크로는 이름에 의한 호출이므로, 이름에 의해 호출돼야 하는 경우에는 매크로를 사용해야 한다.

 

728x90
반응형

관련글 더보기

댓글 영역