VisualStudio的参数为零的参数计数宏

Argument counting macro with zero arguments for VisualStudio

本文关键字:参数 VisualStudio      更新时间:2023-10-16

gcc确实支持## __VA_ARGS__约定中参数为零的参数计数宏。以下是用gcc编译的作品:

#include <stdio.h>
#define NARGS(...) __NARGS(0, ## __VA_ARGS__, 5,4,3,2,1,0)
#define __NARGS(_0,_1,_2,_3,_4,_5,N,...) N
int main()
{
  printf("%dn", NARGS());     // prints 0
  printf("%dn", NARGS(1));    // prints 1
  printf("%dn", NARGS(1, 2)); // prints 2
  return 0;
}

有没有一个VisualC++的等价物可以使用零参数宏?接受非标准的扩展或技巧。

EDIT:修复了使用GCC扩展和C++编译器的示例。

以下示例在启用了非标准扩展的VisualStudio 2010及更新版本、gcc和clang中运行良好。在Microsoft编译器中,它假设当参数计数为零时,预处理器将删除AUGMENTER宏中的尾部逗号。这是非标准的,其他地方也有报道。在gcc和clang中,它使用了众所周知的## __VA_ARGS__非标准扩展。

#include <stdio.h>
#ifdef _MSC_VER // Microsoft compilers
#define EXPAND(x) x
#define __NARGS(_1, _2, _3, _4, _5, VAL, ...) VAL
#define NARGS_1(...) EXPAND(__NARGS(__VA_ARGS__, 4, 3, 2, 1, 0))
#define AUGMENTER(...) unused, __VA_ARGS__
#define NARGS(...) NARGS_1(AUGMENTER(__VA_ARGS__))
#else // Others
#define NARGS(...) __NARGS(0, ## __VA_ARGS__, 5,4,3,2,1,0)
#define __NARGS(_0,_1,_2,_3,_4,_5,N,...) N
#endif
int main()
{
  // NARGS
  printf("%dn", NARGS());          // Prints 0
  printf("%dn", NARGS(1));         // Prints 1
  printf("%dn", NARGS(1, 2));      // Prints 2
  fflush(stdout);
#ifdef _MSC_VER
  // NARGS minus 1
  printf("n");
  printf("%dn", NARGS_1(1));       // Prints 0
  printf("%dn", NARGS_1(1, 2));    // Prints 1
  printf("%dn", NARGS_1(1, 2, 3)); // Prints 2
#endif
  return 0;
}

宏使用真实编译器、Wandbox和Webcompiler 进行了测试

以下是一些可与gcc(5.3)一起使用的代码ANDVisualStudio2010:

#include <stdio.h>
#define expand(x)                          x
#define prefix(...)                        0,##__VA_ARGS__
#define lastof10(a,b,c,d,e,f,g,h,i,j,...)  j
#define sub_nbarg(...)                     expand(lastof10(__VA_ARGS__,8,7,6,5,4,3,2,1,0))
#define nbarg(...)                         sub_nbarg(prefix(__VA_ARGS__))
#define test(...) printf("(%s) ---> %dn",""#__VA_ARGS__,nbarg(__VA_ARGS__))
int main () 
    {
    test() ;              // () ---> 0
    test(1) ;             // (1) ---> 1
    test(1,2) ;           // (1,2) ---> 2
    test(1,2,3) ;         // (1,2,3) ---> 3
    test(1,2,3,4) ;       // (1,2,3,4) ---> 4
    test(1,2,3,4,5) ;     // (1,2,3,4,5) ---> 5
    test(1,2,3,4,5,6) ;   // (1,2,3,4,5,6) ---> 6
    return 0 ;
    }

你能试试吗:

#define __NARGS(_1, _2, _3, _4, _5, VAL, ...) VAL
#define NARGS(...) (sizeof(#__VA_ARGS__) == sizeof("") ? 0 : __NARGS(__VA_ARGS__, 5, 4, 3, 2, 1))

这适用于g++(Demo)。

使用@Jarod42的思想和BOOST的BOOST _PP_VARIADIC_SIZE可以写如下。

#include <stdio.h>
#include <boost/preprocessor/variadic/size.hpp>
#define FOO(...) (sizeof(""#__VA_ARGS__) == sizeof("") ? 0 : BOOST_PP_VARIADIC_SIZE(__VA_ARGS__))
int main()
{
  printf("%dn", FOO());     // prints 0
  printf("%dn", FOO(1));    // prints 1
  printf("%dn", FOO(1, 2)); // prints 2
  return 0;
}