가변 매크로에서 인수를 반복 할 수 있습니까?
C99에서 가변 매크로에 전달 된 인수를 반복하거나 GCC 확장을 사용하여 반복 할 수 있는지 궁금합니다.
예를 들어 구조와 그 필드를 인수로 전달하고 구조 내 각 필드의 이름을 인쇄하는 일반 매크로를 포함 할 수 있습니까?
이 같은 :
struct a { int a; int b; int c; }; / * PRN_STRUCT_OFFSETS는 각 필드의 이름을 인쇄합니다. 첫 번째 인수로 전달 된 구조 내. * / int main (int argc, char * argv []) { PRN_STRUCT_OFFSETS (구조체 a, a, b, c); 반환 0; }
오늘의 숙제는 매크로 트릭에 기반 을두고 있으며 , 오늘은 특히 __VA_NARG__
로랑 Deniau 가 발명 한 것에 대해 배웠습니다 . 어쨌든 다음 샘플 코드는 최대 8 개의 필드에서 작동합니다. 더 필요한 경우 복제하여 코드를 확장하십시오 (이는 전처리 기가 파일을 한 번만 읽었으므로 재귀 기능이 때문입니다).
#include <stdio.h>
#include <stddef.h>
struct a
{
int a;
int b;
int c;
};
struct b
{
int a;
int b;
int c;
int d;
};
#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg
#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2
/* PRN_STRUCT_OFFSETS will print offset of each of the fields
within structure passed as the first argument.
*/
#define PRN_STRUCT_OFFSETS_1(structure, field, ...) printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS_2(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_1(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_3(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_2(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_4(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_3(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_5(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_4(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_6(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_5(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_7(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_6(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_8(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_7(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_NARG(...) PRN_STRUCT_OFFSETS_NARG_(__VA_ARGS__, PRN_STRUCT_OFFSETS_RSEQ_N())
#define PRN_STRUCT_OFFSETS_NARG_(...) PRN_STRUCT_OFFSETS_ARG_N(__VA_ARGS__)
#define PRN_STRUCT_OFFSETS_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define PRN_STRUCT_OFFSETS_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define PRN_STRUCT_OFFSETS_(N, structure, field, ...) CONCATENATE(PRN_STRUCT_OFFSETS_, N)(structure, field, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS(structure, field, ...) PRN_STRUCT_OFFSETS_(PRN_STRUCT_OFFSETS_NARG(field, __VA_ARGS__), structure, field, __VA_ARGS__)
int main(int argc, char *argv[])
{
PRN_STRUCT_OFFSETS(struct a, a, b, c);
printf("\n");
PRN_STRUCT_OFFSETS(struct b, a, b, c, d);
return 0;
}
다음을 인쇄합니다.
struct a:a-0
struct a:b-4
struct a:c-8
struct b:a-0
struct b:b-4
struct b:c-8
struct b:d-12
편집 : 여기에 좀 더 일반적인 시도하는 약간 다른 버전이 있습니다. FOR_EACH(what, ...)
매크로 적용 what
변수 인수 목록의 다른 모든 인수.
따라서 다음과 같이 단일 인수를받는 매크로를 정의하면됩니다.
#define DO_STUFF(x) foo(x)
목록의 모든 인수에 적용됩니다. 따라서 일반적인 예의 경우 약간의 해킹이 필요하지만 여전히 간결합니다.
#define PRN_STRUCT_OFFSETS_(structure, field) printf(STRINGIZE(structure)":"STRINGIZE(field)" - offset = %d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)
그리고 다음과 같이 적용합니다.
FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
마지막으로 완전한 샘플 프로그램 :
#include <stdio.h>
#include <stddef.h>
struct a
{
int a;
int b;
int c;
};
#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg
#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2
#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...)\
what(x);\
FOR_EACH_1(what, __VA_ARGS__);
#define FOR_EACH_3(what, x, ...)\
what(x);\
FOR_EACH_2(what, __VA_ARGS__);
#define FOR_EACH_4(what, x, ...)\
what(x);\
FOR_EACH_3(what, __VA_ARGS__);
#define FOR_EACH_5(what, x, ...)\
what(x);\
FOR_EACH_4(what, __VA_ARGS__);
#define FOR_EACH_6(what, x, ...)\
what(x);\
FOR_EACH_5(what, __VA_ARGS__);
#define FOR_EACH_7(what, x, ...)\
what(x);\
FOR_EACH_6(what, __VA_ARGS__);
#define FOR_EACH_8(what, x, ...)\
what(x);\
FOR_EACH_7(what, __VA_ARGS__);
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__)
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define FOR_EACH_(N, what, x, ...) CONCATENATE(FOR_EACH_, N)(what, x, __VA_ARGS__)
#define FOR_EACH(what, x, ...) FOR_EACH_(FOR_EACH_NARG(x, __VA_ARGS__), what, x, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_(structure, field) printf(STRINGIZE(structure)":"STRINGIZE(field)" - offset = %d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)
int main(int argc, char *argv[])
{
FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
printf("\n");
return 0;
}
고고학자 배지를받을 위험이 있습니다. , 인수 수에 대한 매크로 오버로딩 의 기술을 사용하여 위의 Gregory의 답변이 약간 개선 될 것이라고 생각합니다.
foo.h 사용 :
// Make a FOREACH macro
#define FE_1(WHAT, X) WHAT(X)
#define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
//... repeat as needed
#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) \
GET_MACRO(__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1)(action,__VA_ARGS__)
// Example
// Some actions
#define QUALIFIER(X) X::
#define OPEN_NS(X) namespace X {
#define CLOSE_NS(X) }
// Helper function
#define QUALIFIED(NAME,...) FOR_EACH(QUALIFIER,__VA_ARGS__)NAME
// Emit some code
QUALIFIED(MyFoo,Outer,Next,Inner) foo();
FOR_EACH(OPEN_NS,Outer,Next,Inner)
class Foo;
FOR_EACH(CLOSE_NS,Outer,Next,Inner)
cpp foo.h는 다음을 생성합니다.
Outer::Next::Inner::MyFoo foo();
namespace Outer {namespace Next {namespace Inner {
class Foo;
}}}
구조가 X-Macros 로 설명 된 경우 구조의 모든 필드를 반복하고 내부를 인쇄하는 함수 또는 매크로를 사용할 수 있습니다.
#include <stddef.h> // offsetof macro
//--- first describe the structure, the fields, their types
#define X_FIELDS \
X(int, field1) \
X(int, field2) \
X(char, field3) \
X(char *, field4)
//--- define the structure, the X macro will be expanded once per field
typedef struct {
#define X(type, name) type name;
X_FIELDS
#undef X
} mystruct;
//--- "iterate" over all fields of the structure and print out their offset
void print_offset(mystruct *aStruct)
{
#define X(type, name) printf("offset of %s is %d\n", #name, offsetof(mystruct, name));
X_FIELDS
#undef X
}
//--- demonstrate
int main(int ac, char**av)
{
mystruct a = { 0, 1, 'a', "hello"};
print_offset(&a);
return 0;
}
Gregory Pakosz의 솔루션은 훌륭하게 작동했습니다. 하지만 두 가지 사소한 문제가.
"ISO99는 나머지 인수를지지합니다"라는 경고를받습니다. 이 첫 번째 FOR_EACH_1 매크로의 가변 인수로 인해 발생합니다. 이를 제거하고 FOR_EACH_2에서 FOR_EACH_1에 대한 호출을 변경하면 경고가 제거됩니다.
#define FOR_EACH_1(what, x) #define FOR_EACH_2(what, x, ...)\ what(x); \ FOR_EACH_1(what);
매우 일반적인 방식으로 사용했기 때문에 하나해야의 인수 반복 매크로를 호출했습니다. (나는 항목을 한 번 반복하는 것이 의미가 있음을 의미합니다.)). 많은 것이 문제에 대한 해결책은 매우 간단했습니다. FOR_EACH 매크로에서 x 매개 변수를 제거하기 만하면됩니다.
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
다음은 두 가지 변경 사항이있는 전체 목록입니다.
#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2
#define FOR_EACH_1(what, x) \
what(x)
#define FOR_EACH_2(what, x, ...) \
what(x); \
FOR_EACH_1(what, __VA_ARGS__);
#define FOR_EACH_3(what, x, ...) \
what(x); \
FOR_EACH_2(what, __VA_ARGS__);
#define FOR_EACH_4(what, x, ...) \
what(x); \
FOR_EACH_3(what, __VA_ARGS__);
#define FOR_EACH_5(what, x, ...) \
what(x); \
FOR_EACH_4(what, __VA_ARGS__);
#define FOR_EACH_6(what, x, ...) \
what(x); \
FOR_EACH_5(what, __VA_ARGS__);
#define FOR_EACH_7(what, x, ...) \
what(x); \
FOR_EACH_6(what, __VA_ARGS__);
#define FOR_EACH_8(what, x, ...) \
what(x); \
FOR_EACH_7(what, __VA_ARGS__);
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__)
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define FOR_EACH_(N, what, ...) CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__)
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
varargs를 배열 이니셜 라이저로 사용하고 countof (array)를 반복합니까? 즉, sizeof (배열) / sizeof (배열 [0]). 배열은 강력한으로 C99 익명 배열 일 수 있습니다.
각 var-arg 요소의 텍스트를 처리하는 방법을 모르기 때문에 매크로의 var-arg를 반복하는 다른 방법을 생각할 수 없습니다. var-arg 부분은 CPP, AFAIK로 수행 할 수있는 모든 작업에 대해 쉼표가있는 단일 인수 일 수도 있습니다.
그러나 var-args를 반복하는 아이디어는 다음과 같습니다.
#define countof(a) ( sizeof(a)/sizeof((a)[0]) )
#define MACRO(fd, format, ...) do { int ar_[] = { __VA_ARGS__ }; \
for(int i=0; i<countof(ar_) ; ++i){ \
fprintf(fd, format, ar_[i]); \
} } while(0)
이것은 표준 C에서 생각할 수있는 최고입니다.
#include <stddef.h>
#include <stdio.h>
// prints a single offset
#define PRN_STRUCT_OFFSET(x, a) printf("&" #x "." #a " = %d\n", offsetof(x, a));
// prints a struct with one member
#define PRN_STRUCT_OFFSETS_1(x, a) PRN_STRUCT_OFFSET(x, a)
// prints a struct with two members
#define PRN_STRUCT_OFFSETS_2(x, a, b) \
PRN_STRUCT_OFFSET(x, a) \
PRN_STRUCT_OFFSET(x, b)
// and so on until some N.
// Boost.Preprocessor might help here, I'm not sure
struct some_struct
{
int a;
void* c;
};
int main(void)
{
PRN_STRUCT_OFFSETS_2(struct some_struct, a, c);
return 0;
}
이것은 내 솔루션입니다
즐길 수
#include <stdlib.h>
#include <stdio.h>
#define ITERATE_OVER_VARADICT_MACROS( str, ...)\
do{\
int i, _arr_[] = {__VA_ARGS__};\
fprintf(stderr,"msg =%s\n", str); \
for(i=0; i<sizeof(_arr_)/sizeof(int) ; i++){ \
fprintf(stderr,"_arr_[%d]= %d\n", i, _arr_[i] ); \
}\
}while(0)
int main(int argc, char* argv[])
{
ITERATE_OVER_VARADICT_MACROS("Test of iterate over arguments in variadic macros", 10,12, 34);
return 0;
}
나는 다른 대답으로 추가하고 있습니다. 다음은 g ++ 4.5.0으로 시도 된 C ++ 0x로 시도해.
#include <iostream>
using namespace std;
template<typename L>
inline void for_each(L l)
{
}
template<typename L, typename P, typename... Q>
inline void for_each(L l, P arg, Q... args)
{
l(arg);
for_each(l, args...);
}
int main()
{
for_each([] (int x) { cout << x; }, 1, 2, 3);
return 0;
}
프로그램이 인쇄됩니다.
123
그러나이 접근 방식을 사용하면 int
위의 예에서 람다 식에 전달하는 모든 매개 변수의 형식이 동일해야합니다 . 그러나 람다는 다음과 같은 변수를 사용할 수 있습니다.
int main()
{
int offset = 10;
for_each([offset] (int x) { cout << offset + x << endl; }, 1, 2, 3);
return 0;
}
다음을 인쇄합니다.
11
12
13
당신이 목표로하고 권한을 부여하는 Objective-C
… Github 에서 AWESOME KSVarArgs를 확인하세요.
KSVarArgs는 Objective-C에서 변수 인수를 더 쉽게 처리 할 수 있도록 설계된 매크로 집합입니다. 모든 매크로는 varargs 목록에 object-c 개체 또는 개체와 유사한 구조 (id 유형에 할당 가능) 만 포함되어 있다고 가정합니다. 기본 매크로 ksva_iterate_list ()는 변수 인수를 반복하여 종료 nil을 만날 때까지 각 인수에 대한 블록을 호출합니다. 다른 매크로는 일반 컬렉션으로 변환 할 때 편리합니다.
/*! @param firstNote NSString that is the only known arg
*/
- (void) observeWithBlocks:(NSString*)firstNote,...{
/*! ksva_list_to_nsarray puts varargs into
new array, `namesAndBlocks`
*/
ksva_list_to_nsarray(firstNote, namesAndBlocks);
/// Split the array into Names and Blocks
NSArray *names = [namesAndBlocks subArrayWithMembersOfKind:NSString.class],
*justBlocks = [namesAndBlocks arrayByRemovingObjectsFromArray:names];
[names eachWithIndex:^(id obj, NSInteger idx) {
[self observeName:obj usingBlock:^(NSNotification *n) {
((void(^)())justBlocks[idx])(n);
}];
}];
}
사용 예 :
[NSNotificationCenter.defaultCenter observeWithBlocks:
NSViewFrameDidChangeNotification, /// first, named arg
^(NSNotification *m){ [self respondToFrameChange]; }, // vararg
NSTextViewDidChangeSelectionNotification, // vararg
^(NSNotification *z){ [z.infoDict[@"textView"] save]; }, // vararg
nil // must nil-terminate
];
'ProgramingTip' 카테고리의 다른 글
리플렉션을 사용하여 .NET에서 오버로드 된 메서드를 호출하는 방법 (0) | 2020.11.14 |
---|---|
C #에서 해당하는 블록을 사용하고 있습니까? (0) | 2020.11.14 |
Visual Studio 2010의 전역 소스 코드 제어 무시 패턴에는 무엇이 포함되어야합니까? (0) | 2020.11.14 |
enumerate () -Python에서 생성기 생성 (0) | 2020.11.14 |
현재까지 그루비 노드 (0) | 2020.11.14 |