define 으로 do { ... } while(0) 많이 쓰는 이유
Kernel code 를 보면 do { // some codes.. } while(0) 를 많이 쓰고 있다.
이에 대한 이유를 보면,
1. 빈 구문은 compiler 로 부터 왜 #define FOO do {} while(0). 같이 썼는지 warning 을 받을 수 있다.
(뭔가 구현 중에 있는 code 나 특정 define 이 정의되지 않을 때의 code가 없는 경우에 대체 후, compile 시 알림 같은 것으로 사용이 되려나.. 싶다.)
2. 지역 변수 선언을 위해 쓰는 기본 block 으로 사용될 수 있다.
3. 복잡한 macro를 이용해서 조건부 코드를 만들려고 할 때, 아래와 같이 만들 수 있을 것이다. 이것에 문제점을 보안하기 위해 do-while-0 블락을 사용할 것이다.
#define FOO(x) \ printf("arg is %s\n", x); \ do_something_useful(x);
위의 define으로 조건부 code를 만들어보자. 예를 들어,
if (blah == 2) FOO(blah);
위에서 처럼 만들었다면, interpreter 는 FOO 를 정의된 내용으로 대체를 할 것이다.
if (blah == 2) printf("arg is %s\n", blah); do_something_useful(blah);;
위에서 보듯이 printf 와 do_something_useful() 함수를 같이 쓰려는 목적과는 다르게, blah 가 2일 경우에만 printf 와 do_something_useful 가 같이 불릴 것이다. 이를 예방하기 위해, do { ... } while(0) 으로 define을 해두면,
if (blah == 2) do { printf("arg is %s\n", blah); do_something_useful(blah); } while (0);
위와 같이 변경 될 것이고 한번에 호출 될 수 있을 것이다.
4. 또 다른 예제로는, define으로 지역변수 선언과 사용되는 것을 만들어 놓으면 아래와 같이 구현이 될 것인데(물론 여기에 나온 예제는 간단하고 억지스러움이 있을 수 있다.)
#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }
위의 정의를 아래와 같이 사용한다면,
if (x > y) exch(x,y); // Branch 1 else do_something(); // Branch 2
이런식으로 구현을 하려고 할 것이고 이는 컴파일에 문제가 발생할 것이다. 이유는, 아래와 같이 번역(?) 되기 때문이다.
if (x > y) { // Single-branch if-statement!!! int tmp; // The one and only branch consists tmp = x; // of the block. x = y; y = tmp; } ; // empty statement else // ERROR!!! "parse error before else" do_something();
세미콜론(;) 이 블락이 끝나자 마자 오게되어 발생하는 문제이다. 이것의 해결또한 do { ... } while(0) 으로 해결 할 수 있단다.
if (x > y) do { int tmp; tmp = x; x = y; y = tmp; } while(0); else do_something();
위에서 보듯이 정리가 될 것이다. 이는 습관적인(?) rule 을 통해 code에 문제를 해결하기 위한 것이라 생각이 든다. 이미 kernel에는 많은 do { ... } while(0) 있다.
추가적으로 GCC 는 do-while-0 블락을 대체 할 수 있는 것을 제공한다. 아래와 같이 사용하면 위에서 쓰는 것과 동일한 효과를 보는 것이다.(참고 자료 : http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Statement-Exprs.html#Statement-Exprs)
#define FOO(arg) ({ \ typeof(arg) lcl; \ lcl = bar(arg); \ lcl; \ })
알아두면 편리한 code 작성 법이다. 원본 URL 은 http://kernelnewbies.org/FAQ/DoWhile0 이다.
'Linux Kernel Study' 카테고리의 다른 글
Qemu booted kernel debugging with GDB (0) | 2013.11.22 |
---|---|
[Kernel] current/get_current macro 로 task 정보 얻는 과정. (0) | 2013.10.25 |
Kernel Likely/Unlikely (2) | 2013.10.21 |
나의 첫 kernel patch 등록!!! (0) | 2013.10.17 |
Linux kernel physical memory allocator (Buddy) - Part 3 (0) | 2013.10.04 |