C 프리프로세서는 코멘트를 삭제합니까, 아니면 매크로를 먼저 전개합니까?
이 코드 구조(끔찍한, 끔찍한, 좋지 않은, 매우 나쁜)에 대해 생각해 봅시다.
#define foo(x) // commented out debugging code
// Misformatted to not obscure the point
if (a)
foo(a);
bar(a);
두 컴파일러의 프리프로세서가 이 코드에서 다른 결과를 생성하는 것을 보았습니다.
if (a)
bar(a);
그리고.
if (a)
;
bar(a);
휴대용 코드 베이스에 나쁜 영향을 미치는 것은 분명합니다.
질문입니다.프리프로세서가 이걸 어떻게 해야 하죠?코멘트를 먼저 삭제하시겠습니까, 아니면 매크로를 먼저 확장하시겠습니까?
유감스럽게도 원래의 ANSI C 사양에서는 섹션4의 프리프로세서 기능은 특별히 제외되어 있습니다("이 사양은 C 언어만을 기술하고 있습니다).라이브러리 또는 프리프로세서에는 프로비저닝이 없습니다.")
단, C99 사양은 이 설명을 처리합니다.코멘트는, 「전처리 지시문 해석」전에 행해지는 「변환 단계」의 1개의 스페이스로 치환됩니다.(자세한 내용은 섹션 6.10).
VC++와 GNU C 컴파일러는 모두 이 패러다임을 따르고 있습니다.다른 컴파일러가 오래된 컴파일러일 경우에는 호환성이 없지만 C99에 준거하고 있는 경우에는 안전합니다.
C99 규격의 번역 단계에 대한 이 복사 N 붙여넣기 설명에서 설명한 바와 같이 번역 단계3에서는 코멘트 삭제(단일 공백으로 대체)가 발생하고, 단계4에서는 전처리 지시가 처리되어 매크로가 전개됩니다.
C90 표준(하드 카피에만 있으므로 복사 앤 페이스트하지 않음)에서는 이 두 단계가 같은 순서로 진행됩니다.단, 번역 단계의 설명은 C99 표준과 약간 다릅니다.단, 코멘트가 삭제되어 명령어를 전처리하기 전에1개의 공백 문자로 대체됩니다.확장 매크로도 다르지 않습니다.
마찬가지로 C++ 규격에서는 이들 2개의 단계가 같은 순서로 발생합니다.
//는 C99 같이 C99는 C99로 되어 있습니다
문자 상수, 문자열 리터럴 또는 코멘트 내를 제외하고 // 문자는 다음 줄 바꿈 문자까지 모든 멀티바이트 문자를 포함하지만 포함하지는 않는 코멘트를 도입합니다.
C++ 규격에는 다음과 같이 기술되어 있습니다(2.7).
// 문자는 코멘트를 시작하고 코멘트는 다음 줄바꿈 문자로 끝납니다.
첫 번째 예는 번역자의 오류입니다.;다음 문자foo(a)유지되어야 한다foo()매크로가 확장됩니다.댓글 문자는 다음 항목에 포함되지 않아야 합니다.the foo()매크로를 사용합니다.
단, 번역기가 불편하기 때문에 매크로 정의를 다음과 같이 변경할 수 있습니다.
#define foo(x) /* junk */
에 액세스 할 수 있습니다.
그러나 (그리고 여기서 주제를 벗어나...) 코멘트가 처리되기 전에 라인 스플라이싱(새 라인 직전에 백슬래시)이 발생하기 때문에 다음과 같은 불쾌한 코드에 부딪힐 수 있습니다.
#define evil( x) printf( "hello "); // hi there, \
printf( "%s\n", x); // you!
int main( int argc, char** argv)
{
evil( "bastard");
return 0;
}
누가 썼는지는 모르겠지만
또는 박스형 코멘트를 좋아하는 사람(절대 나는 아니다!)이 쓴 다음 글을 읽어보세요.
int main( int argc, char** argv)
{
//----------------/
printf( "hello "); // Hey, what the??/
printf( "%s\n", "you"); // heck?? /
//----------------/
return 0;
}
사용하시는 컴파일러의 디폴트 처리 여부에 따라서는(컴파일러는 그 처리를 실행하는 거의 모든 사람을 놀라게 하기 때문에, 일부 컴파일러는 디폴트로 그것을 끄기로 합니다), 물론, 어떤 동작이든 원하는 동작을 얻을 수도 있고 하지 않을 수도 있습니다.
MSDN에 따르면 코멘트는 매크로가 확장되는 전처리 단계 이전에 발생하는 토큰화 단계에서 단일 공간으로 대체됩니다.
// 코멘트를 매크로에 넣지 말아 주세요.코멘트를 달 필요가 있는 경우는, /***/ 를 사용합니다.또한 매크로에 오류가 있습니다.
#define foo(x) do { } while(0) /* junk */
이렇게 하면 foo는 항상 사용하기에 안전하다.예를 들어 다음과 같습니다.
if (some condition)
foo(x);
는 foo가 어떤 식에 정의되어 있는지 여부에 관계없이 컴파일러 오류를 발생시키지 않습니다.
#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr / ## / cerr
#endif
는 일부 컴파일러(VC++)에서 동작합니다.언제
_TEST_정의되어 있지 않습니다._cerr...
설명 행으로 대체됩니다.
// cerr...
규정 준수에는 세 가지 단계가 필요한 것으로 기억합니다.
- 벗다
- 매크로를 확장
- 다시 벗다
그 이유는 컴파일러가 .i 파일을 직접 받아들일 수 있기 때문입니다.
언급URL : https://stackoverflow.com/questions/1510869/does-the-c-preprocessor-strip-comments-or-expand-macros-first
'programing' 카테고리의 다른 글
| 렌더링 후 Vue 구성 요소 이벤트 (0) | 2022.07.04 |
|---|---|
| Android M 권한: onRequestPermissionsResult()가 호출되지 않음 (0) | 2022.07.04 |
| String에 있는 Java의 hashCode()는 왜 31을 승수로 사용합니까? (0) | 2022.07.04 |
| Http Servlet Request - 참조 URL을 얻는 방법 (0) | 2022.07.04 |
| Optional.orElse()와 Optional.OrseGet()의 차이점 (0) | 2022.07.04 |