do { ... } while(0) 을 사용하는 이유
do { ... } while(0) 을 사용하는 이유
원문 : https://kernelnewbies.org/FAQ/DoWhile0
리눅스 커널 등의 소스 코드를 보게 되면, "do { ... } while(0)"과 같은 것을 많이 씁니다.
당연히 중괄호 안의 내용이 한 번만 실행되고 끝나는 프로그램인데, 왜 이렇게 만들었을까요?
다음과 같은 이유가 있습니다.
▶ Miller : 빈 구문(empty statement)는 컴파일러가 경고를 냅니다.
▶ Miller : 지역 변수를 선언할 수 있는 구역을 만들어줍니다.
▶ Collins : 조건문을 포함한 코드에서 복잡한 형태의 매크로를 사용할 수 있도록 해줍니다.
#define FOO(x) \ printf("arg is %s\n", x); \ do_something_useful(x); | cs |
위와 같은 매크로를 조건문과 함께 사용하게 된다면,
if (blah == 2) FOO(blah); | cs |
이렇게 사용될 것이고, 이는 곧 다음과 같이 해석됩니다.
if (blah == 2) printf("arg is %s\n", blah); do_something_useful(blah);; | cs |
여기서 문제되는 것은, do_something_useful(blah); 가 조건에 관계없이 수행된다는 점입니다. 이는 원하는 결과가 아닙니다. 하지만, do { ... } while(0) 를 쓴다면 다음과 같이 해석될 것입니다.
if (blah == 2) do { printf("arg is %s\n", blah); do_something_useful(blah); } while (0); | cs |
정확히 원하는 결과를 얻을 수 있게 됩니다.
Miller와 Collins가 지적했듯이, 여러 줄의 코드를 작성하거나
지역 변수를 사용하기 위해 블록 구문을 사용할 수도 있을 것입니다.
하지만, 다음과 같이 일반적인 블록 구문을 쓴다 가정했을 때
#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; } | cs |
하지만 특정한 경우에 위의 코드는 작동하지 않습니다.
아래 코드는 두 개의 조건을 가지는 if 문을 의도한 것입니다.
if (x > y) exch(x,y); // 조건 1 else do_something(); // 조건 2 | cs |
하지만, 이 코드는 단지 하나의 조건만 갖는 if문으로 해석됩니다.
if (x > y) { // if문 int tmp; // 블록으로 구성된 tmp = x; // 하나의 조건문 x = y; y = tmp; } ; // 빈 구문 else // 에러 "parse error before else" do_something(); | cs |
문제는 if문 블록 바로 다음에 나오는 세미콜론(;)입니다.
이 문제의 해결책은 do, while(0) 사이에 위치시키는 것인데,
그러면 컴파일러가 블록 구문이라고 인식하지 않는 블록의 역할을 하는 하나의 구문을 만들 수 있습니다.
변경된 if문은 다음과 같습니다.
if (x > y) do { int tmp; tmp = x; x = y; y = tmp; } while(0); else do_something(); | cs |
gcc에서는 이 do-while-0 구문을 대체할 수 있는 구문 표현을 추가했습니다.
이 표현은 위에 언급한 모든 이점을 갖는 동시에 좀 더 읽기 쉽습니다.
gcc에서 추가된 구문
#define FOO(arg) ({ \ typeof(arg) lcl; \ lcl = bar(arg); \ lcl; \ }) | cs |
'Advanced > C Trick' 카테고리의 다른 글
[C언어] 가변 길이 배열(Variable-length Array)를 사용할 때 (0) | 2021.01.23 |
---|---|
==과 =의 오타를 피하는 방법 (0) | 2016.12.23 |
임시변수 없이 swap 구현하기 (0) | 2016.12.22 |
댓글
이 글 공유하기
다른 글
-
[C언어] 가변 길이 배열(Variable-length Array)를 사용할 때
[C언어] 가변 길이 배열(Variable-length Array)를 사용할 때
2021.01.23 -
==과 =의 오타를 피하는 방법
==과 =의 오타를 피하는 방법
2016.12.23 -
임시변수 없이 swap 구현하기
임시변수 없이 swap 구현하기
2016.12.22