>백엔드 개발 >C++ >MSVC 가변 매크로 확장이 GCC와 다른 이유는 무엇이며 이러한 불일치를 어떻게 극복할 수 있습니까?

MSVC 가변 매크로 확장이 GCC와 다른 이유는 무엇이며 이러한 불일치를 어떻게 극복할 수 있습니까?

Barbara Streisand
Barbara Streisand원래의
2024-11-06 09:10:02882검색

Why does MSVC   variadic macro expansion differ from GCC, and how can we overcome this discrepancy?

MSVC Variadic 매크로 확장

Variadic 매크로는 다양한 확장 기능을 제공하므로 매크로 내에서 여러 인수를 처리할 수 있습니다. GCC에서는 다음과 같은 매크로가 예상대로 작동합니다.

<code class="cpp">#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)

#define FULLY_EXPANDED(count, ...) \
  MAC ## count (__VA_ARGS__)

#define SEMI_EXPANDED(count, ...) FULLY_EXPANDED(count, __VA_ARGS__)

#define EXPAND_THESE(...) SEMI_EXPANDED(VA_NARGS(__VA_ARGS__), __VA_ARGS__)

#define ACTUAL_MACRO(x) parent->GetProperty<x>();
#define MAC1(a) ACTUAL_MACRO(a)
#define MAC2(a,b) MAC1(a) ACTUAL_MACRO(b)
#define MAC3(a,b,c) MAC2(a,b) ACTUAL_MACRO(c)
#define MAC4(a,b,c,d) MAC3(a,b,c) ACTUAL_MACRO(d)
#define MAC5(a,b,c,d,e) MAC4(a,b,c,d) ACTUAL_MACRO(e)</code>

MSVC 확장 동작

그러나 Microsoft의 C 컴파일러(MSVC)에서는 매크로 확장이 다르게 동작합니다. . 각 인수를 개별적으로 확장하는 대신 MSVC는 모든 인수를 단일 표현식으로 연결합니다.

struct MyStructure<br>{<br> void Foo()<br> {</p>
<pre class="brush:php;toolbar:false">EXPAND_THESE(Property1, Property2, Property3, Property4)

}

기본 * 상위;
};

GCC 확장:

{<br> void Foo()<br> {</p><pre class="brush:php;toolbar:false">parent->GetProperty<Property1>(); parent->GetProperty<Property2>(); parent->GetProperty<Property3>(); parent->GetProperty<Property4>();</p> <p>}</p> <p>Base * parent;<br>}<br>

MSVC 확장:

struct MyStructure<br>{<br> void Foo()<br> {</p>
<pre class="brush:php;toolbar:false">parent->GetProperty<Property1, Property2, Property3, Property4>();

}

Base * parent;
}

해결책:

Jeff Walden은 다음을 사용하여 해결 방법을 제안했습니다. 다음 패턴:

<code class="cpp">#define ERRORn(...) ERROR_CHOOSE_HELPERn(COUNT_ARGS_MAX5(__VA_ARGS__), __VA_ARGS__)
#define ERROR_CHOOSE_HELPER1(count) ERROR1
#define ERROR_CHOOSE_HELPER2(count) ERROR2
#define ERROR_CHOOSE_HELPER(count) ERROR_CHOOSE_HELPER##count</code>

이 접근 방식을 사용하려면 원하는 각 가변 매크로 수(예: ERROR1, ERROR2 등)에 대해 CHOOSE_HELPER 매크로를 정의해야 합니다. 그러나 가변 매크로 정의 범위 내에서 각 CHOOSE_HELPER 매크로를 선언하는 것이 중요합니다.

더 간결하고 이식 가능한 솔루션은 다음 기술을 활용하는 것입니다.

<code class="cpp">#define GLUE(x, y) x y

#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count
#define EXPAND_ARGS(args) RETURN_ARG_COUNT args
#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0))

#define OVERLOAD_MACRO2(name, count) name##count
#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count)
#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count)

#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))</code>

이 설정을 사용하면 , 매크로는 다음과 같이 정의할 수 있습니다.

<code class="cpp">#define ERROR1(title) printf("Error: %s\n", title)
#define ERROR2(title, message)\
    ERROR1(title);\
    printf("Message: %s\n", message)
#define ERROR(...) CALL_OVERLOAD(ERROR, __VA_ARGS__)

#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__)</code>

OVERLOAD_MACRO 계층 구조를 사용하면 CHOOSE_HELPER 매크로 정의를 피할 수 있습니다.

위 내용은 MSVC 가변 매크로 확장이 GCC와 다른 이유는 무엇이며 이러한 불일치를 어떻게 극복할 수 있습니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.