2017-03-26 13 views
0

C++ 표준을 사용하여 다음 매크로 정의를 어떻게 해석해야합니까? 주요 문제를 주목하면 오류없이 다음과 같이 AA에 대한 그 교체 목록 (for, S)우리는 어떻게 쉼표로 매크로를 해석해야합니까?

#define AA for, S //<---note the embedded comma 
#define VALUE_TO_STRING(x) ^x! 
#define VALUE(x) VALUE_TO_STRING(x) 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    VALUE(AA) 
    return 0; 
} 

내가 VC++ 2010 테스트하고, 상기 외관의 최종 결과를했던 임베디드 쉼표를 포함하지만, 나는 문제는 결과가 C++ 03 (또는 C++ 11) 표준 사용을 마련하기 위해 수행 한 단계 해석했습니다 :

int wmain(int argc, _TCHAR* argv[]) 
{ 
    ^for, S! 
    return 0; 
} 

내가 VC와 스텝 테스트로 몇 가지 단계를 완료했습니다를 ++ 2010. 우선 첫 번째 단계에서 무슨 일이 벌어지고 있는지 확인하기 위해 2 매크로에서 주석 : 매크로 교체가 똑바로 앞으로

#define AA for, S 
//#define VALUE_TO_STRING(x) ^x! 
#define VALUE(x) VALUE_TO_STRING(x) 

입니다

및 두 개의 인수를 갖는 다른 함수와 같은 매크로처럼 보이는 일련의 산출 :

int wmain(int argc, _TCHAR* argv[]) 
{ 
    VALUE_TO_STRING(for, S) 
    return 0; 
} 

[cpp.rescan]에 따르면 다음 단계는 더 많은 매크로 이름을 위해 이것을 다시 스캔하는 것입니다. 여기에있는 질문은이 새로운 매크로가 2 개의 인수 또는 1 개의 인수 "for, S"을 가진 함수와 같은 매크로로 해석되어야합니다.

정상적인 해석은 VALUE_TO_STRING()에 2 개의 인수가 주어 졌으므로 전 처리기 오류가 발생했다는 것을 고려해야합니다. 그러나 어떻게 VC++가 오류없이 결과를 내놓았 을까요? 분명히 VC++가 취한 두 번째 단계는 for, S을 1 개의 단일 인수로 생각하는 것이 었습니다.이 인수는 의미가 없으며 C++ 표준에 의해 정의되지 않았습니다.

+0

왜 downvote ??? – JavaMan

+0

나는 downvote하지 않았다. 나는 지금 막이 질문을 upvoted, 내 생각에 꽤 어렵지만 명확하고 유용합니다. – Yunnosch

+0

VC++에는 표준 준수 전 처리기가 없습니다. – rici

답변

2

...

은 MS의 프리 프로세서는 표준하지 않았다. They phrase it this odd way :

C99 __func__ 및 전 처리기 규칙 ... C99 전 처리기 규칙의 경우 variadic 매크로가 지원되므로 "부분"이 나열됩니다.

즉, "가변 매크로를 지원하므로 부분적으로 호환 가능합니다." 전처리 기용 AFAIK 표준 준수는 MS 팀에서 매우 낮은 우선 순위로 간주됩니다. 그래서 VC 나 VC++을 표준 전처리 기의 모델로 사용하는 경향이 없습니다. gcc는 표준 전처리 기의 더 나은 모델입니다. 이 이후

난 그냥이 조각에 이야기를 집중하는거야 전처리에 관한 것입니다 :

#define AA for, S 
#define VALUE_TO_STRING(x) ^x! 
#define VALUE(x) VALUE_TO_STRING(x) 
VALUE(AA) 

내가 참조 할 것 ISO-14882 여기에 2011 년 2,003분의 1,998보다 다른 번호를 사용합니다. 이 숫자를 사용하면 확장 단계에서 시작하여 단계별로 진행됩니다. 여기서는 건너 뛸 관련 항목이없는 경우는 제외됩니다.

전처리 기는 이전에 정의 된 함수와 유사한 매크로의 함수와 비슷한 호출 인 VALUE(AA)을 확인합니다. 따라서 먼저 변수를 식별하는 것이고, 16.3 절 4를 참조하십시오 :

[변하지 않는 경우] 함수와 같은 매크로의 호출에서 인수의 수 (전처리 토큰이없는 인수 포함)는 다음과 같아야합니다. 매크로 정의

의 파라미터의 수와 16.3.1 ... 제 1 부분 : 식별 된 함수와 같은 매크로 호출의 인수 후

, 이것

단계에서, 전처리 기는 참으로 하나의 인수가 있음을 나타내며, 매크로는 defi이다. 매개 변수 x이 호출 인수 AA과 일치 함을 나타냅니다. 지금까지 인수 일치 및 x is AA이 모두 발생했습니다.

다음 단계는 인수 확장입니다. 이 단계와 관련하여 대체 목록에서 중요한 것은 매개 변수가 들어있는 위치와 매개 변수가 문자열 화 (# x) 또는 붙여 넣기 (x ## ... 또는 ... ## x)의 일부인지 여부입니다. 대체 목록에없는 인수가있는 경우 다음 이러한 인수가 확장됩니다 (이 단계에서는 인수의 문자열 버전 또는 붙여 넣기 버전이 계산되지 않습니다). 이 확장은 우선 호출이 진행되기 전에 먼저 발생하며 전 처리기가 호출 매개 변수 만 확장하는 것처럼 발생합니다.

이 경우 대체 목록은 VALUE_TO_STRING(x)입니다. 다시 말하지만, VALUE_TO_STRING은 함수와 비슷한 매크로 일 수 있습니다. 그러나 지금 인수 확장을하고 있기 때문에 실제로 신경 쓰지 않습니다. 우리가 신경 쓰는 유일한 것은 x이며 거기에 문자열이나 붙여 넣기되지 않습니다. xAA과 함께 호출되므로 전 처리기는 AAVALUE(AA) 대신 줄에 AA과 같이 평가합니다.AAfor, S으로 확장되는 개체 같은 매크로입니다. 따라서 교체 목록은 VALUE_TO_STRING(for, S)으로 변환됩니다.

, 않는 한 [도 캐릭터 라인 또는 붙여 상기 교체리스트에 파라미터가 내부에 발포 된 [포함 된 모든 매크로 후에 대응하는 인자로 대체되어

이것은 액션 16.3.1 제 1의 나머지이다. ..] 마치 전처리 파일의 나머지 부분을 형성하는 것처럼

지금까지 그렇게 좋았습니다. 그러나 이제는 16.3.4에서 다음 부분에 도달합니다.

대체 목록의 모든 매개 변수가 대체되고 [여기서는 아무 일도 일어나지 않는] 결과 후속 처리 토큰 시퀀스 이 모든 후속 사전 처리 토큰과 함께 다시 스캔됩니다. 대체 할 더 많은 매크로 이름을위한 소스 파일.

이 부분은 전처리 토큰 집합인 것처럼 VALUE_TO_STRING(for, S)을 평가합니다 (단, VALUE은 16.3.4p2 당 매크로이므로 일시 중지된다는 점을 제외하고는 여기에서 설명하지 않습니다). 이 평가는 VALUE_TO_STRING을 함수와 비슷한 매크로로 인식하여 하나처럼 호출되므로 인수 식별이 다시 시작됩니다. VALUE_TO_STRING은 하나의 인수 만 사용하도록 정의되었지만 두 개만 호출됩니다. 그건 실패 16.3 P 4.

0

답변은 확대되는 순서라고 생각합니다.

전처리 확장에 대한 시뮬레이션, 즉 어떤 매크로를 먼저 확장할지에 대한 귀하의 선택은 내 생각에 전처리 기가하는 것과 일치하지 않습니다.

I, (내가 처음에 생각 표준에 따라,하지만 주석이 모순) 프리 프로세서로 작동 순서로 코드를 확장 할 것이다 : 이것은 원래의 프리 프로세서의 결과와 일치

VALUE(AA) 
VALUE_TO_STRING(AA) 
^AA! 
^for, S! 

암호. 이 주문으로는 VALUE_TO_STRING(for, S) 코드를 볼 수 없으며 가장 가까운 코드는 VALUE_TO_STRING(AA)입니다. 이 코드는 인수의 수에 관한 질문을 일으키지 않습니다.

표준에서 아무 것도 인용하지 않았으므로 따옴표로 충분하다고 생각합니다.

아래의 설명에서 언급했듯이, 필자의 답은 이제 전처리 부 전처리를 가정하지 않고도 결과를 설명 할 수있는 시도입니다. 부합하는 행동으로 설명하는 모든 대답은 확실히 좋습니다.

덧붙여서, 컴파일러로서 기능하는 것으로, 값으로부터 캐릭터 라인을 만드는 방법으로서,
^anything!를 이해할 수 없을 것입니다. 하지만 그건 문제가 아니며 최소한의 예를 준비했을 때 그 의미가 상실되었다고 가정합니다. 그것은 물론 완벽하게 완벽합니다. 그러나 인용 매크로 이름으로 확장되는 경우 확장에 영향을 줄 수 있습니다 (예 : "AA". 그렇게되면 확장이 멈추고 그 결과는 무슨 일이 일어 났는지 밝힐 수 있습니다.내가 VC++ 2010로 테스트를 완료했습니다

+0

설명 된 단계는 표준 준수 컴파일러에 의해 수행되지 않을 수 있습니다. 단락 [cpp.subst] 이후로 : "대체되기 전에, 각 인수의 전처리 토큰은 완전히 매크로 대체됩니다 ...". 따라서 "AA"매크로가 먼저 대체되어야합니다. VALUE – JavaMan

+0

사실 저는 ^! # 연산자로 인한 문제를 피할 수 있습니다. 내가 처음 사용한 코드는 다음과 같습니다 #define VALUE_TO_STRING (x) #x – JavaMan

+0

@JavaMan 나는 당신의 주장을 받아들입니다. 고마워. 고마워. 따라서 전처리 기가 제가했던 것처럼 작동한다면, 그것은 순응하지 않습니다. 예상치 못한 결과에 대한 가능한 설명으로 답을 남겨 둘 것입니다. 어떤 대답이라도 표준을 기반으로 한 설명이 있다면 그것은 그것이받은 모든 상향 음을 가치가 있습니다. – Yunnosch