标签: variadic-macros

GCC的标准替代## __ VA_ARGS__技巧?

C99中的可变参数宏存在一个众所周知的 空args 问题.

例:

#define FOO(...)       printf(__VA_ARGS__)
#define BAR(fmt, ...)  printf(fmt, __VA_ARGS__)

FOO("this works fine");
BAR("this breaks!");
Run Code Online (Sandbox Code Playgroud)

BAR()根据C99标准,上述用途确实不正确,因为它将扩展到:

printf("this breaks!",);
Run Code Online (Sandbox Code Playgroud)

请注意尾随逗号 - 不可行.

一些编译器(例如:Visual Studio 2010)将悄然摆脱那个尾随的逗号.其他编译器(例如:GCC)支持放在##前面__VA_ARGS__,如下所示:

#define BAR(fmt, ...)  printf(fmt, ##__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

但有没有符合标准的方法来获得这种行为?也许使用多个宏?

现在,该##版本似乎得到了相当好的支持(至少在我的平台上),但我真的更喜欢使用符合标准的解决方案.

先发制人:我知道我可以写一个小功能.我正在尝试使用宏来做到这一点.

编辑:以下是我想要使用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);
Run Code Online (Sandbox Code Playgroud)

这会自动为我的BAR()日志记录语句添加换行符,假设fmt它始终是双引号C字符串.它不会将换行符打印为单独的printf(),如果日志记录是行缓冲的并且异步来自多个源,则这是有利的.

c c99 c-preprocessor variadic-macros

141
推荐指数
6
解决办法
7万
查看次数

C++预处理器__VA_ARGS__参数个数

简单的问题,我无法在网上找到答案.在可变参数宏中,如何查找参数的数量?如果它有解决方案,我可以使用boost预处理器.

如果它有所不同,我试图转换可变数量的宏参数来增强预处理器序列,列表或数组以进行进一步的重新处理.

c c++ c-preprocessor variadic-macros

90
推荐指数
8
解决办法
10万
查看次数

MSVC不会正确扩展__VA_ARGS__

考虑以下代码:

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) F(__VA_ARGS__)
F(1, 2, 3)
G(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

X = 1 and VA_ARGS = 2, 3两个宏的预期输出,这就是我用GCC得到的,但是,MSVC将其扩展为:

X = 1 and VA_ARGS = 2, 3
X = 1, 2, 3 and VA_ARGS =
Run Code Online (Sandbox Code Playgroud)

也就是说,__VA_ARGS__将其扩展为单个参数,而不是分解为多个参数.

有什么方法吗?

visual-c++ c-preprocessor variadic-macros

48
推荐指数
2
解决办法
1万
查看次数

可以通过参数的数量来重载宏吗?

如何做这项工作?如何实现C99/C++ 11可变参数宏以根据给出多少参数来扩展到不同的东西?

c c++ overloading c-preprocessor variadic-macros

41
推荐指数
3
解决办法
1万
查看次数

Variadic宏是非标准的吗?

对于debugbuilds,我通常使用Clang,因为它更好地格式化警告和错误,并使它更容易跟踪它们并修复它们.

但最近在添加了具有可变参数的宏之后,Clang告诉我以下内容(来自虚拟项目):

main.cpp:5:20: warning: named variadic macros are a GNU extension [-Wvariadic-macros]
#define stuff3(args...)  stuff_i(args)
Run Code Online (Sandbox Code Playgroud)

我知道macroname(args...)在各种编译器中编译很好,包括Visualstudio,Sunstudio,当然还有GCC.但是为了确保clang是正确的,我尝试了另外两种扩展可变参数的方法:

1号:

#define stuff1(...)  stuff_i(...)
Run Code Online (Sandbox Code Playgroud)

2号:

#define stuff2(...)  stuff_i(__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

我都收到这条消息:

main.cpp:3:16: warning: variadic macros were introduced in C99 [-Wvariadic-macros]
Run Code Online (Sandbox Code Playgroud)

...这让我想知道Variadic宏是否实际上是C++标准的一部分(当然我知道预处理器是独立解释的)?

c++ c-preprocessor variadic-macros

32
推荐指数
2
解决办法
2万
查看次数

使用模板元编程的更好的LOG()宏

典型的基于LOG()宏的日志记录解决方案可能如下所示:

#define LOG(msg) \
    std::cout << __FILE__ << "(" << __LINE__ << "): " << msg << std::endl 
Run Code Online (Sandbox Code Playgroud)

这允许程序员使用方便且类型安全的流操作符创建数据丰富的消息:

string file = "blah.txt";
int error = 123;
...
LOG("Read failed: " << file << " (" << error << ")");

// Outputs:
// test.cpp(5): Read failed: blah.txt (123)
Run Code Online (Sandbox Code Playgroud)

问题是这会导致编译器内联多个ostream :: operator <<调用.这会增加生成的代码,从而增加函数大小,我怀疑这可能会损害指令缓存性能并阻碍编译器优化代码的能力.

这是一个"简单"替代方案,它通过调用可变参数模板函数替换内联代码:

********* 解决方案#2:VARIADIC模板功能 *********

#define LOG(...) LogWrapper(__FILE__, __LINE__, __VA_ARGS__)

// Log_Recursive wrapper that creates the ostringstream
template<typename... Args>
void LogWrapper(const char* file, int line, const Args&... …
Run Code Online (Sandbox Code Playgroud)

c++ logging variadic-templates variadic-macros c++11

30
推荐指数
1
解决办法
1万
查看次数

MSVC++可变宏扩展

所以我有一个在GCC中运行良好的宏,但在微软的C++编译器中没有.我希望有人可能知道一种解决方法,或者也许可以向我解释它为什么会这样.

我确定这个宏并不完全是"标准",但它确实会帮助我.

这是宏的一个功能示例:

#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)
Run Code Online (Sandbox Code Playgroud)

以下是我如何使用此宏:

struct MyStructure
{
  void Foo()
  {
    EXPAND_THESE(Property1, Property2, Property3, Property4)
  }

  Base * parent;
}
Run Code Online (Sandbox Code Playgroud)

以下是GCC如何扩展上述内容:

struct MyStructure
{
  void …
Run Code Online (Sandbox Code Playgroud)

c++ visual-c++ c-preprocessor variadic-macros

22
推荐指数
3
解决办法
7977
查看次数

变量宏,零参数

我正在研究一个调用宏,

#define CALL(f,...) FN(f)->call((ref(new LinkedList()), __VA_ARGS__))
Run Code Online (Sandbox Code Playgroud)

在被叫时,

CALL(print,2,3,4,5);
Run Code Online (Sandbox Code Playgroud)

将2 3 4 5添加到链接列表(,重载以执行此操作)并调用print,其中需要链接列表按预期工作,但有些调用不需要参数,

CALL(HeapSize);
Run Code Online (Sandbox Code Playgroud)

它仍然需要一个链接列表,但是一个空的,上面不起作用,我试图想出一个宏,它可以使用任何一种风格吗?

编辑:挖掘gcc文档我发现在VA_ARGS之前添加## 会删除,当没有参数但是我无法嵌套宏时,

CALL(print,CALL(HeadSize));
Run Code Online (Sandbox Code Playgroud)

如果我分离它的工作调用,这会导致CALL未定义错误

c++ gcc c-preprocessor variadic-macros

20
推荐指数
4
解决办法
2万
查看次数

有没有办法用Visual C++中的可变参数列表编写宏?

据我所知,在gcc中你可以写下这样的东西:

#define DBGPRINT(fmt...) printf(fmt);
Run Code Online (Sandbox Code Playgroud)

有没有办法在VC++中做到这一点?

c++ visual-c++ c-preprocessor variadic-macros

16
推荐指数
1
解决办法
2万
查看次数

附加到__VA_ARGS__

我知道我可以这样做:

#define MACRO(api, ...) \
  bool ret = api(123, ##__VA_ARGS__);
Run Code Online (Sandbox Code Playgroud)

这只是一个例子,它是更复杂的解决方案的一部分.关键是我需要将可变数量的参数附加到第一个123. ##使编译器在123参数之后删除逗号,如果没有参数传递给MACRO.

但现在我想向api附加参数,如下:

#define MACRO(api, ...) \
  bool ret = api(__VA_ARGS__##, 456);
Run Code Online (Sandbox Code Playgroud)

诺坎多.一种解决方案是使用两个宏,MACRO和MACRO_V,并使_V版本不处理任何参数.但有没有办法让它与一个宏一起工作?

c gcc c-preprocessor variadic-macros

13
推荐指数
2
解决办法
7426
查看次数