GCC의 ##_VA_에 대한 표준 대안ARGS__ 트릭?
C99에 있는 변이성 매크로의 빈 아그에는 잘 알려진 문제가 있다.
예:
#define FOO(...) printf(__VA_ARGS__)
#define BAR(fmt, ...) printf(fmt, __VA_ARGS__)
FOO("this works fine");
BAR("this breaks!");
의 사용BAR()
위의 내용은 C99 표준에 따르면 다음과 같이 확장될 것이기 때문에 정확하지 않다.
printf("this breaks!",);
후행 쉼표를 기록해 두십시오. 작동하지 않음.
일부 컴파일러(예: Visual Studio 2010)는 여러분을 위해 그 후행 쉼표를 조용히 없앨 것이다.기타 컴파일러(예: GCC) 지원 퍼팅##
앞에__VA_ARGS__
, like so:
#define BAR(fmt, ...) printf(fmt, ##__VA_ARGS__)
하지만 이런 행동을 취할 수 있는 표준적인 방법이 있을까?여러 개의 매크로를 사용하는 게 어때?
지금 당장.##
버젼은 (적어도 내 플랫폼에서는) 꽤 잘 지원되는 것 같지만, 나는 오히려 표준 규격의 솔루션을 사용하고 싶다.
선제: 나는 내가 작은 기능만 쓸 수 있다는 것을 안다.매크로를 이용해서 하려고 해.
편집: BAR()을 사용하는 이유의 예(단순하지만)는 다음과 같다.
#define BAR(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);
이렇게 하면 자동으로 내 BAR() 로깅 문에 새 줄이 추가되며,fmt
항상 두 개의 구분이 있는 C현이다.별도의 인쇄f()로 뉴라인을 인쇄하지 않으며, 이는 로깅이 회선 버퍼링되고 여러 소스에서 비동기식으로 전송되는 경우에 유리하다.
네가 사용할 수 있는 논쟁의 셈법이 있다.
다음은 두 번째 표준 준수 방법BAR()
jwd 질문의 예:
#include <stdio.h>
#define BAR(...) printf(FIRST(__VA_ARGS__) "\n" REST(__VA_ARGS__))
/* expands to the first argument */
#define FIRST(...) FIRST_HELPER(__VA_ARGS__, throwaway)
#define FIRST_HELPER(first, ...) first
/*
* if there's only one argument, expands to nothing. if there is more
* than one argument, expands to a comma followed by everything but
* the first argument. only supports up to 9 arguments but can be
* trivially expanded.
*/
#define REST(...) REST_HELPER(NUM(__VA_ARGS__), __VA_ARGS__)
#define REST_HELPER(qty, ...) REST_HELPER2(qty, __VA_ARGS__)
#define REST_HELPER2(qty, ...) REST_HELPER_##qty(__VA_ARGS__)
#define REST_HELPER_ONE(first)
#define REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__
#define NUM(...) \
SELECT_10TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway)
#define SELECT_10TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, ...) a10
int
main(int argc, char *argv[])
{
BAR("first test");
BAR("second test: %s", "a string");
return 0;
}
이 같은 수법은 다음과 같은 경우에 사용된다.
설명
그 전략은 분리하는 것이다.__VA_ARGS__
첫 번째 주장과 나머지 주장으로 (있는 경우)이렇게 하면 첫 번째 논쟁 이후 두 번째 논쟁(있는 경우) 앞에 내용을 삽입할 수 있다.
FIRST()
이 매크로가 단순히 첫 번째 주장으로 확장되어 나머지는 버린다.
구현이 간단하다.그throwaway
을 논증하는 것이 확실하다FIRST_HELPER()
두 개의 인수를 얻는데, 이 인수는...
하나라도 필요해하나의 주장으로 다음과 같이 확대된다.
FIRST(firstarg)
FIRST_HELPER(firstarg, throwaway)
firstarg
2개 이상이면 다음과 같이 팽창한다.
FIRST(firstarg, secondarg, thirdarg)
FIRST_HELPER(firstarg, secondarg, thirdarg, throwaway)
firstarg
REST()
이 매크로는 첫 번째 인수(두 개 이상의 인수가 있는 경우 첫 번째 인수 뒤의 쉼표 포함)를 제외한 모든 것으로 확장된다.
이 매크로의 실행은 훨씬 더 복잡하다.일반적인 전략은 인수의 수(1개 또는 1개 이상)를 세어 다음 중 하나로 확장하는 것이다.REST_HELPER_ONE()
(한 개의 주장만 주어진 경우) 또는REST_HELPER_TWOORMORE()
(두 개 이상의 인수가 주어진 경우).REST_HELPER_ONE()
간단히 무로 확장 - 첫 번째 이후 논쟁은 없으므로, 나머지 논쟁은 빈 집합이다.REST_HELPER_TWOORMORE()
또한 간단하다. 첫 번째 주장을 제외한 모든 것이 쉼표로 확장된다.
인수는 다음 항목을 사용하여 계산된다.NUM()
이는 매로 된다. 이 매크로는 다음으로 확장된다.ONE
단 하나의 주장만 주어진다면,TWOORMORE
두 개에서 아홉 개 사이의 주장이 주어지고, 10개 이상의 주장이 주어지면 깨진다(10번째 주장으로 확대되기 때문에).
그NUM()
매크로 사용SELECT_10TH()
매크로: 인수 수를 결정한다.이름에서 알 수 있듯이SELECT_10TH()
간단히 10번째 주장으로 확대하다줄임표 때문에SELECT_10TH()
최소한 11개의 주장을 통과시킬 필요가 있다(표준은 줄임표에는 적어도 하나의 주장이 있어야 한다고 말한다).이래서다.NUM()
통과하다throwaway
마지막 주장으로서(없이는, 하나의 주장을 에 넘기다)NUM()
단지 10개의 주장만이 에 전달될 것이다.SELECT_10TH()
표준에 위반될 수 있다.
둘 중 하나 선택REST_HELPER_ONE()
또는REST_HELPER_TWOORMORE()
연결에 의해 이루어진다.REST_HELPER_
의 NUM(__VA_ARGS__)
에REST_HELPER2()
한다.REST_HELPER()
을 확실히 하기 위함이다NUM(__VA_ARGS__)
와 연결되기 전에 완전히 확장된다.REST_HELPER_
.
하나의 논거로 확장하면 다음과 같다.
REST(firstarg)
REST_HELPER(NUM(firstarg), firstarg)
REST_HELPER2(SELECT_10TH(firstarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg)
REST_HELPER2(ONE, firstarg)
REST_HELPER_ONE(firstarg)
- (iii)
둘 이상의 인수를 가진 확장은 다음과 같다.
REST(firstarg, secondarg, thirdarg)
REST_HELPER(NUM(firstarg, secondarg, thirdarg), firstarg, secondarg, thirdarg)
REST_HELPER2(SELECT_10TH(firstarg, secondarg, thirdarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg, secondarg, thirdarg)
REST_HELPER2(TWOORMORE, firstarg, secondarg, thirdarg)
REST_HELPER_TWOORMORE(firstarg, secondarg, thirdarg)
, secondarg, thirdarg
GCC의 을 수 수 있다.,##__VA_ARGS__
만약 당신이 이 질문에 대한 리차드 핸슨의 대답에 설명된 바와 같이, 당신이 당신의 변이성 매크로의 수에 대한 어떤 하드 코드화된 상한을 기꺼이 받아들이려고 한다면 당신은 당신의 변이성 매크로에 전달할 수 있다.그러나 내가 아는 한 그러한 제한을 가지지 않으려면 C99 지정 전처리 기능만 사용할 수 없다. 언어에 대한 일부 확장을 사용해야 한다.clang과 ic는 이 GCC 확장을 채택했지만 MSVC는 채택하지 않았다.
2001년에 나는 표준화를 위한 GCC 확장명(그리고 당신이 다른 이름을 사용할 수 있는 관련 확장명)을 작성했다.__VA_ARGS__
문서 N976의 rest-parameter)를 위해, 그러나 위원회로부터 아무런 응답도 받지 못했다; 나는 누가 그것을 읽었는지조차 모른다.2016년에 그것은 N2023년에 다시 제안되었고, 나는 그 제안이 어떻게 우리에게 논평에서 알려질지 아는 모든 사람들을 격려한다.
디버그 인쇄에 사용하는 매우 간단한 매크로:
#define DBG__INT(fmt, ...) printf(fmt "%s", __VA_ARGS__);
#define DBG(...) DBG__INT(__VA_ARGS__, "\n")
int main() {
DBG("No warning here");
DBG("and we can add as many arguments as needed. %s", "nice!");
return 0;
}
아무리 많은 논거가 DBG에 전달되더라도 c99 경고는 없다.
은.DBG__INT
다음과 같이 더미 매개 변수 추가...
c99는 항상 적어도 하나의 논쟁을 가지고 있고 c99는 충족된다.
사용 중인 경우gcc 8+
clang 6+
또는MSVC 2019
(출처), 그러면 (출처)도 사용할 수 있다.__VA_OPT__
매크로(macro)는 다음과 같은 경우에 조건부로 확장된다.__VA_ARGS__
비흡수적이다.
그래서 우리는 그 둘을 변환시킬 수 있다.FOO
그리고BAR
매크로 하나:
#define FOO(s, ...) printf(s __VA_OPT__(,) __VA_ARGS__)
그래서,FOO("hello!")
로 확대될 것이다.printf("hello!")
그리고FOO("x = %d", 5)
로 확대될 것이다.printf("x = %d", 5)
.
이는 비교적 새로운 기능이기 때문에(C++2a에 소개됨) 컴파일러가 아직 지원하지 않을 수 있다.
c++11 이상을 사용할 수 있고 매크로를 함수 호출로 확장하려는 경우, 예를 들어 다음과 같이 래퍼를 만들 수 있다.
#define BAR(fmt, ...) printf(fmt, __VA_ARGS__)
로 변환할 수 있다.
#define BAR(fmt, ...) BAR_wrapper(fmt)(__VA_ARGS__)
어디에BAR_wrapper
다음과 같이 정의할 수 있다.
struct BAR_wrapper_t {
BAR_wrapper_t(const char* fmt) : fmt(fmt) {}
const char* fmt;
int operator()() const { return printf(fmt); }
template <typename... Args>
int operator()(Args&& args) const { return printf(fmt, std::forward<Args>(args)...); }
};
inline BAR_wrapper_t BAR_wrapper(const char* fmt) { return BAR_wrapper_t(fmt); }
이것은 내가 사용하는 단순화된 버전이다.그것은 여기 있는 다른 답들의 훌륭한 기술에 기초하고 있으며, 그들에게는 다음과 같은 많은 소품들이 있다.
#define _SELECT(PREFIX,_5,_4,_3,_2,_1,SUFFIX,...) PREFIX ## _ ## SUFFIX
#define _BAR_1(fmt) printf(fmt "\n")
#define _BAR_N(fmt, ...) printf(fmt "\n", __VA_ARGS__);
#define BAR(...) _SELECT(_BAR,__VA_ARGS__,N,N,N,N,1)(__VA_ARGS__)
int main(int argc, char *argv[]) {
BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);
return 0;
}
바로 그겁니다.
다른 해결책과 마찬가지로 이것은 매크로의 인수 수로 제한된다.더 많이 지원하려면 에 더 많은 매개 변수를 추가하십시오._SELECT
, 그리고 그 이상N
논쟁들인수 이름이 카운트다운(위쪽 대신)되어 카운트 기반임을 상기시키는 역할을 함SUFFIX
논쟁은 역순으로 제공된다.
이 솔루션은 0개의 인수를 하나의 인수로 간주한다.그렇게BAR()
명목상 "작업"으로 확장되기 때문에_SELECT(_BAR,,N,N,N,N,1)()
로 확장되는._BAR_1()()
로 확장되는.printf("\n")
.
원한다면 의 사용으로 창의력을 얻을 수 있다._SELECT
다른 수의 인수에 대해 서로 다른 매크로를 제공한다.예를 들어, 여기에 형식보다 먼저 '수준' 인수를 사용하는 LOG 매크로가 있다.포맷이 누락되면 (메시지 없음), 인수가 1개만 있으면 "%s"를 통해 로그하고, 그렇지 않으면 포맷 인수를 나머지 인수의 인쇄f 형식 문자열로 처리한다.
#define _LOG_1(lvl) printf("[%s] (no message)\n", #lvl)
#define _LOG_2(lvl,fmt) printf("[%s] %s\n", #lvl, fmt)
#define _LOG_N(lvl,fmt, ...) printf("[%s] " fmt "\n", #lvl, __VA_ARGS__)
#define LOG(...) _SELECT(_LOG,__VA_ARGS__,N,N,N,2,1)(__VA_ARGS__)
int main(int argc, char *argv[]) {
LOG(INFO);
LOG(DEBUG, "here is a log message");
LOG(WARN, "here is a log message with param: %d", 42);
return 0;
}
/* outputs:
[INFO] (no message)
[DEBUG] here is a log message
[WARN] here is a log message with param: 42
*/
현재 상황에서(최소한 하나의 인수가 존재하지만 0은 존재하지 않음) 정의 가능BAR
로서BAR(...)
, Jens Gustedt's 사용 HAS_COMMA(...)
쉼표를 탐지한 다음 에 발송하다BAR0(Fmt)
또는BAR1(Fmt,...)
이에 따라서
다음 내용:
#define HAS_COMMA(...) HAS_COMMA_16__(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0)
#define HAS_COMMA_16__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define CAT_(X,Y) X##Y
#define CAT(X,Y) CAT_(X,Y)
#define BAR(.../*All*/) CAT(BAR,HAS_COMMA(__VA_ARGS__))(__VA_ARGS__)
#define BAR0(X) printf(X "\n")
#define BAR1(X,...) printf(X "\n",__VA_ARGS__)
#include <stdio.h>
int main()
{
BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);
}
와 화해하다.-pedantic
예고 없이
일반적인 솔루션은 아니지만, 인쇄물의 경우 다음과 같은 새로운 라인을 추가할 수 있다.
#define BAR_HELPER(fmt, ...) printf(fmt "\n%s", __VA_ARGS__)
#define BAR(...) BAR_HELPER(__VA_ARGS__, "")
나는 그것이 형식 문자열에서 참조되지 않는 모든 추가 아그를 무시한다고 생각한다.그래서 당신은 아마도 다음과 같은 일을 할 수 있을 것이다.
#define BAR_HELPER(fmt, ...) printf(fmt "\n", __VA_ARGS__)
#define BAR(...) BAR_HELPER(__VA_ARGS__, 0)
나는 C99가 이것을 하기 위한 표준적인 방법 없이 승인되었다는 것을 믿을 수 없다.AFAICT는 C++11에도 문제가 존재한다.
부스트 같은 것을 이용해서 이 구체적인 사건을 처리하는 방법이 있다.전처리기.BUUST_PP_VARIRADIGH_를 사용할 수 있다.SIZE: 인수 목록의 크기를 확인한 다음 다른 매크로로 조건부 확장이것의 한 가지 단점은 0과 1의 주장을 구별할 수 없다는 것이며, 그 이유는 다음과 같은 점을 고려하면 명확해진다.
BOOST_PP_VARIADIC_SIZE() // expands to 1
BOOST_PP_VARIADIC_SIZE(,) // expands to 2
BOOST_PP_VARIADIC_SIZE(,,) // expands to 3
BOOST_PP_VARIADIC_SIZE(a) // expands to 1
BOOST_PP_VARIADIC_SIZE(a,) // expands to 2
BOOST_PP_VARIADIC_SIZE(,b) // expands to 2
BOOST_PP_VARIADIC_SIZE(a,b) // expands to 2
BOOST_PP_VARIADIC_SIZE(a, ,c) // expands to 3
빈 매크로 인수 목록은 실제로 비어 있는 하나의 인수로 구성된다.
이 경우, 원하는 매크로에는 항상 인수가 1개 이상 있으므로 운이 좋으며, 두 개의 "과부하" 매크로로 구현할 수 있다.
#define BAR_0(fmt) printf(fmt "\n")
#define BAR_1(fmt, ...) printf(fmt "\n", __VA_ARGS__)
그리고 그 사이를 전환하는 또 다른 매크로(예:
#define BAR(...) \
BOOST_PP_CAT(BAR_, BOOST_PP_GREATER(
BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1))(__VA_ARGS__) \
/**/
또는
#define BAR(...) BOOST_PP_IIF( \
BOOST_PP_GREATER(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1), \
BAR_1, BAR_0)(__VA_ARGS__) \
/**/
어느 것이든 더 읽기 쉽다고 생각되는 것(인수의 매크로를 과부하할 수 있는 일반적인 형태를 제공하는 것이 첫 번째가 좋다).
변수 인수 목록에 액세스하고 변경함으로써 하나의 매크로로도 이 작업을 수행할 수 있지만, 읽기 쉽지는 않으며, 이 문제에 매우 구체적이다.
#define BAR(...) printf( \
BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__) "\n" \
BOOST_PP_COMMA_IF( \
BOOST_PP_GREATER(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1)) \
BOOST_PP_ARRAY_ENUM(BOOST_PP_ARRAY_POP_FRONT( \
BOOST_PP_VARIADIC_TO_ARRAY(__VA_ARGS__)))) \
/**/
또한 왜 BUUST_PP_ARRY_ENUM_TROGING이 없는가?그것은 이 해결책을 훨씬 덜 끔찍하게 만들 것이다.
편집: 자, 여기 BUUST_PP_ARRY_ENUM_TROGING 버전이 있고, 이 버전을 사용하는 버전(이 버전이 내가 가장 좋아하는 솔루션임):
#define BOOST_PP_ARRAY_ENUM_TRAILING(array) \
BOOST_PP_COMMA_IF(BOOST_PP_ARRAY_SIZE(array)) BOOST_PP_ARRAY_ENUM(array) \
/**/
#define BAR(...) printf( \
BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__) "\n" \
BOOST_PP_ARRAY_ENUM_TRAILING(BOOST_PP_ARRAY_POP_FRONT( \
BOOST_PP_VARIADIC_TO_ARRAY(__VA_ARGS__)))) \
/**/
나도 최근에 비슷한 문제에 부딪혔는데, 해결책이 있다고 믿어.
핵심 아이디어는 매크로를 쓰는 방법이 있다는 겁니다.NUM_ARGS
변동 매크로가 주어진 인수의 수를 계산한다.의 변형을 사용할 수 있다.NUM_ARGS
NUM_ARGS_CEILING2
변이성 매크로에 1개의 인수가 주어지는지 2개 이상의 인수가 주어지는지를 알려줄 수 있다.그러면 너는 너의 글을 쓸 수 있다.Bar
하다.NUM_ARGS_CEILING2
그리고CONCAT
두 개의 도우미 매크로(정확히 1개의 인수를 예상하는 것과 1개 이상의 변수 개수를 예상하는 것) 중 하나에 인수를 보내는 것.
매크로를 쓰기 위해 이 트릭을 사용하는 예는 다음과 같다.UNIMPLEMENTED
, 이것은 매우 비슷하다.BAR
:
1단계:
/**
* A variadic macro which counts the number of arguments which it is
* passed. Or, more precisely, it counts the number of commas which it is
* passed, plus one.
*
* Danger: It can't count higher than 20. If it's given 0 arguments, then it
* will evaluate to 1, rather than to 0.
*/
#define NUM_ARGS(...) \
NUM_ARGS_COUNTER(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, \
12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define NUM_ARGS_COUNTER(a1, a2, a3, a4, a5, a6, a7, \
a8, a9, a10, a11, a12, a13, \
a14, a15, a16, a17, a18, a19, a20, \
N, ...) \
N
1.5단계:
/*
* A variant of NUM_ARGS that evaluates to 1 if given 1 or 0 args, or
* evaluates to 2 if given more than 1 arg. Behavior is nasty and undefined if
* it's given more than 20 args.
*/
#define NUM_ARGS_CEIL2(...) \
NUM_ARGS_COUNTER(__VA_ARGS__, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 1)
2단계:
#define _UNIMPLEMENTED1(msg) \
log("My creator has forsaken me. %s:%s:%d." msg, __FILE__, \
__func__, __LINE__)
#define _UNIMPLEMENTED2(msg, ...) \
log("My creator has forsaken me. %s:%s:%d." msg, __FILE__, \
__func__, __LINE__, __VA_ARGS__)
3단계:
#define UNIMPLEMENTED(...) \
CONCAT(_UNIMPLEMENTED, NUM_ARGS_CEIL2(__VA_ARGS__))(__VA_ARGS__)
CONCAT가 통상적인 방법으로 구현되는 경우.짧은 힌트로서, 위의 내용이 혼란스러워 보이면, CONCAT의 목표는 다른 매크로 "통화"로 확장하는 것이다.
NUM_ARGS 자체는 사용되지 않는다는 점에 유의하십시오.여기에 기본적인 요령을 설명하기 위해 포함시켰을 뿐이다.Jens Gustedt의 P99 블로그를 참조해 좋은 대접을 받으십시오.
두 가지 참고 사항:
NUM_ARGS는 처리하는 인수 수에 제한이 있다.내 것은 20개까지만 처리할 수 있지만, 그 수는 완전히 임의적이다.
NUM_ARGS는 표시된 바와 같이 인수가 0이면 1을 반환한다는 점에서 함정이 있다.그 요지는 NUM_ARGS가 기술적으로 [commas + 1]을 세고 있는 것이지 아그가 아니라는 것이다.이 특별한 경우에, 그것은 실제로 우리에게 유리하게 작용한다._UNIMPLIMITED1은 빈 토큰을 잘 처리할 것이며 _UNIMPLIMITED0을 써야 하는 것을 절약할 수 있다.구스테트도 그 방법을 알고 있지만, 나는 그것을 사용하지 않았고 우리가 여기서 하는 일에 효과가 있을지 확실하지 않다.
C(gcc), 762바이트
#define EMPTYFIRST(x,...) A x (B)
#define A(x) x()
#define B() ,
#define EMPTY(...) C(EMPTYFIRST(__VA_ARGS__) SINGLE(__VA_ARGS__))
#define C(...) D(__VA_ARGS__)
#define D(x,...) __VA_ARGS__
#define SINGLE(...) E(__VA_ARGS__, B)
#define E(x,y,...) C(y(),)
#define NONEMPTY(...) F(EMPTY(__VA_ARGS__) D, B)
#define F(...) G(__VA_ARGS__)
#define G(x,y,...) y()
#define STRINGIFY(...) STRINGIFY2(__VA_ARGS__)
#define STRINGIFY2(...) #__VA_ARGS__
#define BAR(fmt, ...) printf(fmt "\n" NONEMPTY(__VA_ARGS__) __VA_ARGS__)
int main() {
puts(STRINGIFY(NONEMPTY()));
puts(STRINGIFY(NONEMPTY(1)));
puts(STRINGIFY(NONEMPTY(,2)));
puts(STRINGIFY(NONEMPTY(1,2)));
BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);
}
가정:
- 쉼표 또는 괄호를 포함하는 arg 없음
- 포함하지 않음
A
~G
(하드_노트로 이름을 바꿀 수 있음)
표준 용액은 다음과 같다.FOO
대신에BAR
. 재주문 논쟁의 몇 가지 이상한 경우들이 있다. 그것은 아마도 당신에게 도움이 되지 않을 것이다(하지만, 누군가 분해하고 재조립할 수 있는 영리한 해킹을 생각해 낼 수 있을 것이라고 장담한다.__VA_ARGS__
조건부로 그 안에 있는 인수의 수에 근거하여!) 그러나 일반적으로 사용FOO
"보통"은 그냥 통한다.
참조URL: https://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick
'Programing' 카테고리의 다른 글
Java SafeVargs 주석, 표준 또는 모범 사례가 있는가? (0) | 2022.04.26 |
---|---|
Vue v-model.lazy 또는 @change가 내 Vue 데이터를 업데이트하지 않음 (0) | 2022.04.26 |
최대 절전 모드에서의 서로 다른 저장 방법의 차이점은? (0) | 2022.04.26 |
이 항목에 대한 액세스.Vuex 스토어에서 $apollo, NUXT에서 vue-apollo? (0) | 2022.04.26 |
JPA 및 최대 절전 모드 - 기준 대 JPQL 또는 HQL (0) | 2022.04.25 |