UFO ET IT

이 매크로가 10 대신 20으로 대체되는 이유는 무엇입니까?

ufoet 2020. 11. 16. 23:17
반응형

이 매크로가 10 대신 20으로 대체되는 이유는 무엇입니까?


1. #define NUM 10
2. #define FOO NUM
3. #undef NUM
4. #define NUM 20
5. 
6. FOO

전처리기만 실행하면 출력 파일에 20 개가 포함됩니다.

그러나 내가 이해하는 바에 따르면 전처리 기는 단순히 텍스트 교체를 수행합니다. 그래서 이것은 내가 생각하는 것입니다 (분명히 잘못되었지만 idky).

  1. NUM은 10으로 정의됩니다.
  2. 따라서 2 행에서 NUM은 10으로 대체됩니다. 이제 "#define FOO 10"이 있습니다.
  3. NUM이 정의되지 않았습니다.
  4. NUM이 재정의되어 이제 20입니다.
  5. FOO는 라인 4의 재정의 이전 인 라인 2에 따라 대체되며 10입니다.

그래서 출력은 20이 아니라 10이되어야한다고 생각합니다. 무엇이 잘못되었는지 설명 할 수 있습니까?


표준에서 모든 관련 사양을 수집하기 위해 주석 스레드에서이 정보를 추출하고 N4527 초안을 기반으로 C ++ 섹션 번호를 추가했습니다 (표준 텍스트는 두 표준에서 동일 함). 표준 (들)은 주제에 대해 절대적으로 명확합니다.

  1. #define 전 처리기 지시문은 매크로 대체를 거치지 않습니다.

    (C11 §6.10¶7; C ++ §16 [cpp] ¶6) : 전처리 지시문 내의 전처리 토큰은 달리 명시되지 않는 한 매크로 확장의 영향을받지 않습니다.

  2. 매크로가 대체 텍스트로 바뀌면 새 텍스트가 다시 검색됩니다. 프로그램의 해당 지점에 토큰에 대한 활성 매크로 정의가있는 경우 대체의 전 처리기 토큰이 매크로로 확장됩니다.

    (C11 §6.10.3¶9; C ++ §16.3 [cpp.replace] ¶9) 형식의 전처리 지시문

    # define identifier replacement-list new-line

    매크로 이름의 각 후속 인스턴스가 지시문의 나머지를 구성하는 전처리 토큰의 대체 목록으로 대체되도록 하는 객체와 유사한 매크로정의합니다 . 그런 다음 아래에 지정된대로 더 많은 매크로 이름을 찾기 위해 교체 목록을 다시 검색합니다.

  3. 매크로 정의는 다음과 같은 라인에서 활성화되어 #define까지를 #undef매크로 이름 또는 파일의 끝.

    (C11 §6.10.3.5¶1; C ++ §16.3.5 [cpp.scope] ¶1) 매크로 정의는 해당 #undef지시문을 만날 때까지 (블록 구조와 무관) 지속됩니다 . 전처리 번역 단위. 매크로 정의는 번역 단계 4 이후에는 의미가 없습니다.

프로그램을 보면 :

#define NUM 10
#define FOO NUM
#undef NUM
#define NUM 20
FOO 

NUM1 행 의 매크로 정의가 3 행까지 정확히 지속 된다는 것을 알 수 있습니다. 해당 행에는 대체 가능한 텍스트가 없으므로 정의가 사용되지 않습니다. 결과적으로 프로그램은 다음과 실질적으로 동일합니다.

#define FOO NUM
#define NUM 20
FOO 

이 프로그램의 세 번째 줄에는 FOO, with replacement list NUM및 for NUM, with replacement list 의 활성 정의가 20있습니다. FOO그것을 만드는 그 교체리스트로 치환 NUM한 후, 즉 다시 초래 매크로 스캔 NUM최종 결과가 해당하므로, 여분 다시 재검사되는 것을 그 교체리스트 (20)로 대체되고 있지만 정의 매크로 거기 토큰 20은 번역 단계 5에서 처리 할 수 ​​있습니다.


텍스트 대체는 .NET Framework를 작성한 곳이 아니라 매크로가 사용되는 곳에서 이루어집니다 #define. 사용하는 시점에서 FOO, 그것은 대체 FOONUM하고 NUM현재로 정의된다 20.


에:

FOO

전처리 기는이를로 교체 NUM한 다음 NUM현재 정의 된 것으로 교체 20합니다.

처음 네 줄은 다음과 같습니다.

#define FOO NUM 
#define NUM 20

C11 표준은 다음과 같이 말합니다 (다른 버전의 C 및 C ++도 비슷하게 말합니다).

양식의 전처리 지시문은 # define identifier replacement-list new-line매크로 이름의 각 후속 인스턴스가 지시문의 나머지를 구성하는 전처리 토큰의 대체 목록으로 대체되도록하는 객체와 유사한 매크로를 정의합니다. 그런 다음 아래에 지정된대로 더 많은 매크로 이름을 찾기 위해 교체 목록을 다시 검색합니다.

However it also says in another part (thanks to rici for pointing this out).

The preprocessing tokens within a preprocessing directive are not subject to macro expansion unless otherwise stated.

So a subsequent instance of the macro name which is found inside another #define directive is actually not replaced.

Your line #define FOO NUM defines that when the token FOO is later found (outside of another #define directive!), it will be replaced by the token NUM .

After a token is replaced, rescanning occurs, and if NUM is itself a macro, then NUM is replaced at that point. (And if whatever NUM expands to contains macros , then that gets expanded , and so on).

So your sequence of steps is actually:

  1. NUM defined as 10
  2. FOO defined as NUM
  3. NUM undefined and re-defined as 20
  4. FOO expands to NUM
  5. (rescan) NUM expands to 20

This behaviour can be seen in another common preprocessor trick, to turn the defined value of a macro into a string:

#define STR(X) #X
#define STR_MACRO(X) STR(X)
#define NUM 10

puts( STR_MACRO(NUM) );     // output: 10

If we had written puts( STR(NUM) ) then the output would be NUM.

The output of 10 is possible because, as before, the second #define here does not actually expand out STR. So the sequence of steps in this code is:

  1. STR(X) defined as #X
  2. STR_MACRO(X) defined as STR(X)
  3. NUM defined as 10
  4. STR_MACRO and NUM are both expanded; the result is puts( STR(10) );
  5. (Rescan result of last expansion) STR(10) is expanded to "10"
  6. (Rescan result of last expansion) No further expansion possible.

참고URL : https://stackoverflow.com/questions/32147438/why-is-this-macro-replaced-as-20-instead-10

반응형