[완료] #define 문장에서의 ##용법
글쓴이: zipsinworm / 작성시간: 화, 2007/05/01 - 9:18오전
Windows소스를 분석하다가 #define문의 ##용법에 대해 궁금증이 생겼습니다.
예를들어,
#define CAT(a,b) a##b
int main(void)
{
int arr={100,200};
printf("%d",CAT(arr,[1]);
return 0;
}
라는 소스가 있다고 하면 출력 결과는 200이 나와야 한다고 생각합니다.
그런데 Linux(SUSE)에서 저 소스를 컴파일 하니 CAT(arr,[1]) 이 문장에서 [ <- 이것을 파싱하지 못한다고
에러가 나왔습니다.
게다가, 다른 소스
printf("%s",CAT("HAHA","haha")라는 문장도 출력 결과가 HAHAhaha가 나와야 하는데 컴파일시 에러가 발생합니다.
그 외에 함수나 변수등을 테스트 해보니 컴파일시 에러도 안나고 출력결과도 정확히 나옵니다. 문자열과 배열만
컴파일시 에러가 발생합니다.
컴파일시 에러가 안나오게 하는 방법은 없을까요?
Forums:
##는 여러 개를
##는 여러 개를 이어서 하나의 토큰을 만들어낼 때 사용합니다.
위의 경우 arr[1]에서 arr, [, 1, ] 모두 별도의 토큰이므로 ##로 붙이는 게 아닙니다. 스트링 두 개도 이은다고 하나의 토큰이 되지는 않구요.
----
익명이나 오래전 글에 리플은 무조건 -1
그런데...
Windows VC++에서 위 소스를 C 컴파일을 사용해 컴파일하면 잘 돌아갑니다.
물론 printf("%s",CAT("HAHA","haha")); 도 잘 돌아가고요.
그런데 Linux에서 컴파일 하면 에러가 납니다.
arr[1]가 모두 별도의 토큰이라는 말씀은 이해가 가는데 ##로 붙이는게 아니라면 어떻게 붙이는지, 그리고
스트링 두개도 잇는다고 하나의 토큰이 되지 않는다면 어떻게 하나의 토큰으로 만들어 붙이는지 궁금합니다.
> Windows VC++에서 위
> Windows VC++에서 위 소스를 C 컴파일을 사용해 컴파일하면 잘 돌아갑니다.
>
> 물론 printf("%s",CAT("HAHA","haha")); 도 잘 돌아가고요.
>
## 로 생성되는 토큰이 유효한 토큰이 아닐 경우 행동이 정의되지 않기
때문에 맘대로 행동할 수 있습니다. MSVC 의 경우 유효하지 않은 토큰을
억지로 단일 토큰으로 만들어 오류로 인식하기 보다는 임의로 분리된
토큰으로 인식하기를 선택한 것입니다.
>
> 그런데 Linux에서 컴파일 하면 에러가 납니다.
>
> arr[1]가 모두 별도의 토큰이라는 말씀은 이해가 가는데 ##로 붙이는게 아니라면 어떻게 붙이는지, 그리고
>
토큰에 대해 뭔가 오해를 하고 계신 것 같습니다. 전처리 과정에서
토큰에는 다음과 같은 6가지 종류가 있습니다. (실제론 7가지이지만, 설명
에 오해만 불러일으킬 수 있는 한 가지는 일부러 뺍니다.)
- 명칭(identifier)
- pp-number
- 문자열 상수(string literal)
- 문자 상수(character constant)
- 구두점(punctuator)
- 헤더명(header name)
arr[1] 은 명칭(arr), 구두점([), pp-number(1), 구두점(]) 의 4개의 토큰
으로 구성되어 있습니다. 즉, 토큰 별로 구분해 쓰면 "arr" "[" "1" "]" 이
됩니다. arr 과 [ 사이에 ## 를 넣어 토큰 연결을 시도 한다는 것은 "arr["
라는 하나의 토큰을 만드려는 것에 해당합니다. "arr[" 는 과연 위에서
언급한 부류 중 어디에 속할 수 있을까요? 없습니다. 따라서 유효하지 않은
토큰이 되고 그 이후 컴파일러는 자기 나름대로의 판단에 따라 행동할 수
있게 됩니다 (gcc 는 오류로 처리하길 선택한 것이며, MSVF 는 "arr[" 를
다시 "arr" "[" 로 찢어 2개 올바른 토큰으로 인식해 처리한 것입니다).
> 스트링 두개도 잇는다고 하나의 토큰이 되지 않는다면 어떻게 하나의 토큰으로 만들어 붙이는지 궁금합니다.
>
"abc" ## "def" 의 경우에도 동일한 이야기가 적용됩니다. (이번에는
하나의 토큰을 구분하기 위해 [] 를 사용합니다.) ["abc"]["def"] 는
유효한 2개의 string literal 이지만, ["abc""def"] 는 유효하지 않은
토큰이 됩니다.
문자열 상수의 내용을 합해 하나의 문자열로 만들고자 한다면 이미 다른
분이 적어주신 방법을 사용하시면 됩니다. 단, 그와 같은 방식의 문자열
연결은 전처리 과정 이후에 이루어지는 것이기 때문에 "전처리기에서는"
문자열 연결의 효과를 볼 수 없습니다.
그럼...
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
"HAHA" "haha"는 그냥
"HAHA" "haha"는 그냥 "HAHA" "haha"라고만 써도 잘 됩니다.
따라서 이런 용도에는 #define CAT(a, b) a b 쓰면 됩니다.
arr[1]도 마찬가지로 알고 있습니다. 전처리기가 arr [1]로 바꿔주니까요.
##는 이럴때 쓰는거겠죠.
결과: 10
ANSI 이전의 컴파일러를 위한 트릭으로는 a/**/b가 있는데
ANSI 표준에 의해 /**/는 빈칸 하나로 치환되어 a b(ab가 아닌)가 되므로
ANSI 이전의 컴파일러에만 쓸수 있다고 알고있습니다.
(즉, 호환성을 위한 방법이 아님.)
절망으로 코딩하고 희망으로 디버깅하자.
Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.
"HAHA" "haha"는 그냥
실수로 두개 올렸습니다.
절망으로 코딩하고 희망으로 디버깅하자.
Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.
확실히 알겠습니다.
전웅님께서 말씀하신것이 확실히 이해가 된다음 cppig1995님께서 예를 들어주신것이 쐐기를 박았네요.
전처리 과정에서의 토큰해석에 관해서 모르고 있었는데 중요한 점을 찍어주셔서
감사합니다!!
댓글 달기