IT이야기

다양한 매크로에서 논쟁을 반복하는 것이 가능한가?

cyworld 2022. 5. 15. 23:44
반응형

다양한 매크로에서 논쟁을 반복하는 것이 가능한가?

나는 C99에 변동성 매크로로 전달된 주장이나 GCC 확장을 사용하는 것에 대해 반복할 수 있는지 궁금했다.

예를 들어, 구조와 그 필드가 인수로서 전달되고 구조 내의 각 필드의 오프셋을 인쇄하는 일반적인 매크로의 쓰기가 가능한가?

이와 비슷한 것:

{을 구성하다.a에;에;in b;inc;};
/* PRN_STRUCT_OFFSETS가 각 필드의 오프셋을 인쇄함제1의 논거로 통과된 구조 내에서
*/
주(int argc, char *argv[]){PRN_STRUCT_OFFETS(구조 a, a, b, c);
반환 0;}

고고학자 배지를 얻을 위험을 무릅쓰고, 나는 논쟁의 수에 대한 과부하 매크로의 기법을 사용하는 위의 그레고리의 대답에 약간의 개선이 있다고 생각한다.

foo랑.h:

// Make a FOREACH macro
#define FE_0(WHAT)
#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(_0,_1,_2,_3,_4,_5,NAME,...) NAME 
#define FOR_EACH(action,...) \
  GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(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;
}}}

오늘의 숙제는 매크로 트릭에 바탕을 둔 것인데, 오늘 나는 특히 로랑 데니우에 의해 발명된 것에 대해 배웠다.어쨌든 다음의 샘플 코드는 명료성을 위해 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;
}

만약 당신의 구조가 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;
}

그레고리 파코스의 해결책은 효과가 좋았다.그러나 나는 두 가지 사소한 문제가 있었다.

  1. 현학적인 옵션으로 컴파일해서 경고 받았어. "ISO99에는 쉼표 인수를 사용해야 한다."이는 첫 번째 FOR_AKE_1 매크로의 변수 인수에 의해 발생한다.이 경고를 제거하고 FOR_AKE_2에서 FOR_AKE_1로 통화를 변경하면 이 경고가 제거된다.

    #define FOR_EACH_1(what, x) 
    #define FOR_EACH_2(what, x, ...)\
        what(x);                    \
        FOR_EACH_1(what);
    
  2. 아주 일반적인 방법으로 사용했기 때문에, 나는 때때로 오직 하나의 주장만으로 반복 매크로를 불러야 했다. (한 항목을 1번 반복하는 것은 이치에 맞지 않는다는 것을 안다;)다행히도 이 문제에 대한 해결책은 꽤 간단했다.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__)

바라그를 배열 이니셜라이저로 사용하고 (배열) 카운트오버를 반복하시겠습니까?즉, 크기(배열)/크기(배열[0]).어레이는 잠재적으로 C99 익명 어레이일 수 있다.

각 바-아그 요소의 본문을 어떻게 해야 할지 모르기 때문에 나는 매크로의 바-아그에 대해 반복하는 다른 방법을 생각할 수 없다.바-아그 부분은 CPP, AFAIK와 함께 할 수 있는 모든 것에 대해 쉼표가 있는 하나의 주장일 수 있다.

하지만 여기 바아그스를 반복하는 내 아이디어가 있다.

#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)

또 다른 답으로 덧붙이는 겁니다.여기에 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-CGithub에서 AWEST KSVArgs를 확인해 보십시오.

KSVArgs는 목표-C에서 변수 인수를 보다 쉽게 처리할 수 있도록 설계된 매크로 세트다.모든 매크로는 바그 리스트에 목적-c 객체 또는 객체-유형 구조(타입 ID에 할당 가능)만 포함된다고 가정한다.기본 매크로 ksva_itrate_list()는 변수 인수에 대해 반복하여 각 인수에 대해 블록을 호출하며 종료 영에 도달할 때까지 반복한다.다른 매크로들은 일반 컬렉션으로 변환할 때 편리함을 위해 사용된다.

/*! @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
]; 

이것이 내가 생각할 수 있는 가장 좋은 것이다, 표준 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;
}

비워두려면 다음과 같이 하십시오.__VA_ARGS__GNU 확장을 사용할 수 있다.##_VA_ARGS__ https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

참조URL: https://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros

반응형