C 언어에서 기본적으로 매크로가 확장된 내용은 전처리기 지시자로 동작을
하지 못하기 때문에 #pragma 의 경우 실제 프로그램에 사용하면서 불편함
을 겪는 일이 잦아, 전처리기 지시자는 아니면서 최종적으로 매크로
확장된 결과가 전처리기 지시자처럼 동작하게 하는 _Pragma 전처리기
연산자를 추가했습니다 (이로써 #, ##, _Pragma 3개의 연산자가 존재하게
됩니다).
아래는 gcc 에서의 예입니다. 해당 환경이 C99 을 부분적이라도 지원하는
경우라면 _Pragma 를 사용하실 수 있습니다. 물론, 추후 컴파일러가 C99
을 지원하는 한 계속 유효하기 때문에 forward compatibility 도 매우
좋습니다.
매크로가 확장된 결과가 전처리기 지시자와 동일한 형태를 가져도
전처리기 지시자 역할을 하지 않는다는 것은 표준에 의해 "명시된" 사항
입니다.
보여주신 코드는 표준에 따라 다음과 같이 해석할 수 있습니다.
우선, PACKING 이 #pragma pack(1) 로 확장됩니다. (PACKING(a) 의 경우
에도 동일한 해석이 적용됩니다) 전처리 단계가 끝나면 (개념상) 모든
전처리기 지시자를 지우고 다음 단계로 넘어가야 하지만, PACKING 이
확장해 나온 결과는 전처리기 지시자가 "아니기" 때문에 소스에 남아
있게 됩니다. (전처리를 거친 후에 "진짜로" 소스에 남아 있다는 뜻이
아닙니다. 지금 어떻게 컴파일러가 비일관적인 행동을 할 수 있는지
개념적인 해석을 쫓고 있는 것입니다.)
그럼 전처리 이후 단계에서 #pragma pack(1) 을 만나게 되지만, 전처리
이후 단계에서 #pragma pack(1) 은 적법한 구조가 아닙니다. 따라서
문법 위반이 되며 컴파일러는 적절한 메시지를 출력한 후에 원하는 대로
행동할 수 있는 자유를 얻게 됩니다. 따라서 그렇게 남은 #pragma
pack(1) 을 무시하든 인식하든 컴파일러 자유입니다 - 따라서 보여주신
두 코드의 행동이 모두 커버됩니다.
단, 진단 메시지는 반드시 출력해주어야 합니다! 만약 사용하고 계시는
컴파일러가 두 코드에 대해 아무런 진단 메시지를 출력해주지 않는다면
표준을 따르지 않는 구현체가 됩니다 - 일단, 표준을 따르지 않는 구현체
라면 더 이상 표준을 놓고 논할 필요가 없어집니다. 즉, 그런 구현체가
구현한 언어는 표준 C 언어가 아니라 C 언어랑 비슷한 어떤 언어가 되는
것뿐입니다. ;-)
다시 말해, 보여주신 코드에서 "function-like macro 가 아닌 object-like
macro 인 경우에는 원하는대로 동작하더라" 라는 결론은 크게 의미가
없습니다. 어차피 표준을 따르지 않는 컴파일러거나 (메시지를 출력해
표준에 부합하는 경우에도) 해당 코드가 의존하는 행동이 가장 위험하다는
undefined behavior 이기 때문에 컴파일러 개발자가 어느날 기분이 우울해
그 기능을 바꾸거나 없애 버려도 개발자는 할 말이 없습니다. 따라서
PACK 만 쓰려는 목적으로도 "절대 피해야" 하는 구조입니다 - 제가 가지고
있는 컴파일러 모두가 두 코드 다 번역을 해주지 않는군요.
애초부터 이처럼 매크로를 확장한 결과가 전처리기 지시자로 동작할 수
있다는 사실이 (잘못된 행동을 의미하는) undefined behavior 가 아니라
(좀 더 의미있는 이식성을 보여주는) implementation-defined 였다면
표준이 애써 _Pragma 를 도입하지도 않았을 것입니다.
아마 안될 것 같네요..
굳이 쓰려면 include를 써야 될 것 같습니다.
--- pragma_pack.h begin -----
#ifndef USE_PACK
#define USE_PACK
#pragma pack(1)
#endif
--- pragma_pack.h end -----
#include "pragma_pack.h"
struct _Test
{
};
컴파일러에 따라
컴파일러에 따라 다르겠지만
제생각엔 pragma 같은 경우엔 가능할것 같습니다.
pragma 는 전처리기가 사용하눈 부분이 아니라 컴파일러가 사용하는 부분이기 때문에 전처리기는 그대로 놔두는것 같더군요.
-- 아쉬운 하루 되세요 --
-- 아쉬운 하루 되세요 --
매크로 확장 결과를
매크로 확장 결과를 전처리기 지시어(preprocessing directive)로 해석할 수 없습니다. (ISO C Standard Sec 6.1 참고) 따라서 질문하신 내용은 불가능합니다.
원할 경우, m4(1)와 같은 프리프로세서를 써서 소스를 가공한 다음 컴파일러에 전달하는 방법도 있습니다. m4는 autoconf(1) 등에서 사용하는 인기있는?? 프리프로세서입니다.
--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
정확히 그 목적을
정확히 그 목적을 위해 탄생한 것이 C99 의 _Pragma 연산자입니다.
C 언어에서 기본적으로 매크로가 확장된 내용은 전처리기 지시자로 동작을
하지 못하기 때문에 #pragma 의 경우 실제 프로그램에 사용하면서 불편함
을 겪는 일이 잦아, 전처리기 지시자는 아니면서 최종적으로 매크로
확장된 결과가 전처리기 지시자처럼 동작하게 하는 _Pragma 전처리기
연산자를 추가했습니다 (이로써 #, ##, _Pragma 3개의 연산자가 존재하게
됩니다).
아래는 gcc 에서의 예입니다. 해당 환경이 C99 을 부분적이라도 지원하는
경우라면 _Pragma 를 사용하실 수 있습니다. 물론, 추후 컴파일러가 C99
을 지원하는 한 계속 유효하기 때문에 forward compatibility 도 매우
좋습니다.
참고로 _Test 처럼 밑줄과 대문자로 시작하는 명칭은 표준과 구현체에
예약된 것으로 사용하는 자체로 해당 프로그램의 이식성을 현저히
떨어뜨립니다. 굳이 그럴 필요가 없다면 일반적인 형태의 명칭을 사용
하시기 바랍니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
제가 예전에
제가 예전에 비슷한짓을 한것 같았는데 전웅님이 아니라고 하니까 상당히 민망했습니다.
그래서 해봤는데 안되는건 안되더군요
그리고 되는건 또 되네요 ㅜ.ㅜ
제가 원한건 이런 방식이었습니다.
아쉽게도 이건 실폐했습니다
그러나 다음과 같은건 되네요
한마디로 인자가 없는 녀석은 가능하다.
인자가 있는녀석은 불가능하다. -_-;;
어쨓든 PACK만을 쓰시려는 목적으론 괜찮을듯도 합니다.
PACK_1, PACK_2 PACK_4 머 이런식으로요 ^^
-- 아쉬운 하루 되세요 --
-- 아쉬운 하루 되세요 --
매크로가 확장된
매크로가 확장된 결과가 전처리기 지시자와 동일한 형태를 가져도
전처리기 지시자 역할을 하지 않는다는 것은 표준에 의해 "명시된" 사항
입니다.
보여주신 코드는 표준에 따라 다음과 같이 해석할 수 있습니다.
우선, PACKING 이 #pragma pack(1) 로 확장됩니다. (PACKING(a) 의 경우
에도 동일한 해석이 적용됩니다) 전처리 단계가 끝나면 (개념상) 모든
전처리기 지시자를 지우고 다음 단계로 넘어가야 하지만, PACKING 이
확장해 나온 결과는 전처리기 지시자가 "아니기" 때문에 소스에 남아
있게 됩니다. (전처리를 거친 후에 "진짜로" 소스에 남아 있다는 뜻이
아닙니다. 지금 어떻게 컴파일러가 비일관적인 행동을 할 수 있는지
개념적인 해석을 쫓고 있는 것입니다.)
그럼 전처리 이후 단계에서 #pragma pack(1) 을 만나게 되지만, 전처리
이후 단계에서 #pragma pack(1) 은 적법한 구조가 아닙니다. 따라서
문법 위반이 되며 컴파일러는 적절한 메시지를 출력한 후에 원하는 대로
행동할 수 있는 자유를 얻게 됩니다. 따라서 그렇게 남은 #pragma
pack(1) 을 무시하든 인식하든 컴파일러 자유입니다 - 따라서 보여주신
두 코드의 행동이 모두 커버됩니다.
단, 진단 메시지는 반드시 출력해주어야 합니다! 만약 사용하고 계시는
컴파일러가 두 코드에 대해 아무런 진단 메시지를 출력해주지 않는다면
표준을 따르지 않는 구현체가 됩니다 - 일단, 표준을 따르지 않는 구현체
라면 더 이상 표준을 놓고 논할 필요가 없어집니다. 즉, 그런 구현체가
구현한 언어는 표준 C 언어가 아니라 C 언어랑 비슷한 어떤 언어가 되는
것뿐입니다. ;-)
다시 말해, 보여주신 코드에서 "function-like macro 가 아닌 object-like
macro 인 경우에는 원하는대로 동작하더라" 라는 결론은 크게 의미가
없습니다. 어차피 표준을 따르지 않는 컴파일러거나 (메시지를 출력해
표준에 부합하는 경우에도) 해당 코드가 의존하는 행동이 가장 위험하다는
undefined behavior 이기 때문에 컴파일러 개발자가 어느날 기분이 우울해
그 기능을 바꾸거나 없애 버려도 개발자는 할 말이 없습니다. 따라서
PACK 만 쓰려는 목적으로도 "절대 피해야" 하는 구조입니다 - 제가 가지고
있는 컴파일러 모두가 두 코드 다 번역을 해주지 않는군요.
애초부터 이처럼 매크로를 확장한 결과가 전처리기 지시자로 동작할 수
있다는 사실이 (잘못된 행동을 의미하는) undefined behavior 가 아니라
(좀 더 의미있는 이식성을 보여주는) implementation-defined 였다면
표준이 애써 _Pragma 를 도입하지도 않았을 것입니다.
따라서 계속 민망해 하셔도 좋습니다 (농담입니다!!!) ^^
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
아, 그리고 아깐 바로
아, 그리고 아깐 바로 회식 달려가느라 못 쓰고 퇴근했습니다만, sizeof
연산자의 결과는 size_t 로 implementation 이 정하는 무부호 정수형
입니다.
따라서 printf() 로 출력할 경우 (C90 의 경우) 적절한 변환이나 (C99 의
경우) 적절한 size modifier 가 필요합니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
댓글 달기