是否可以迭代可变参数宏中的参数?
我想知道是否可以迭代传递给 C99 中的可变参数宏的参数或使用任何 GCC 扩展?
例如,是否可以编写一个通用宏,它采用一个结构及其作为参数传递的字段,并打印结构内每个字段的偏移量?
像这样的东西:
struct a { int a; int b; int c; }; /* PRN_STRUCT_OFFSETS will print offset of each of the fields within structure passed as the first argument. */ int main(int argc, char *argv[]) { PRN_STRUCT_OFFSETS(struct a, a, b, c); return 0; }
I was wondering if it is possible to iterate over arguments passed to a variadic macro in C99 or using any GCC extensions ?
For e.g. is it possible to write a generic macro that takes a structure and its fields passed as arguments and prints offset of each field within the structure ?
Something like this:
struct a { int a; int b; int c; }; /* PRN_STRUCT_OFFSETS will print offset of each of the fields within structure passed as the first argument. */ int main(int argc, char *argv[]) { PRN_STRUCT_OFFSETS(struct a, a, b, c); return 0; }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
这是我今天的作业,它基于宏观技巧,今天我特别学习了
__VA_NARG__
由 Laurent Deniau 发明。无论如何,为了清楚起见,以下示例代码最多可处理 8 个字段。如果需要更多,只需通过复制来扩展代码(这是因为预处理器不具有递归功能,因为它只读取文件一次)。打印出:
编辑:这是一个稍微不同的版本,试图变得更通用。
FOR_EACH(what, ...)
宏应用what 到变量参数列表中的每个其他参数。
因此,您只需定义一个带有单个参数的宏,如下所示:
它将应用于列表中的每个参数。
因此,对于您的典型示例,您需要进行一些修改,但仍然保持简洁:
然后像这样应用它:
最后,一个完整的示例程序:
Here is my homework of the day, it's based on macro tricks and today I particularly learnt about
__VA_NARG__
invented by Laurent Deniau. Anyway, the following sample code works up to 8 fields for the sake of clarity. Just extend the code by duplicating if you need more (this is because the preprocessor doesn't feature recursion, as it reads the file only once).which prints out:
EDIT: Here is a slightly different version that tries to be more generic. The
FOR_EACH(what, ...)
macro applieswhat
to every other argument in the variable argument list.So, you just have to define a macro that takes a single argument like this:
which is going to be applied to every argument in the list.
So, for your typical example you need to hack a bit but it still remains concise:
And you apply it like this:
Finally, a complete sample program:
冒着获得考古学家徽章的风险,我认为格雷戈里的答案(链接)使用来自根据参数数量重载宏
使用 foo.h:
cpp foo.h 生成:
At the risk of earning an archaeologist badge, I think there is a minor improvement to Gregory's answer (link) using the technique from Overloading Macro on Number of Arguments
With foo.h:
cpp foo.h generates:
如果您的结构是用 X-Macros 描述的,那么可以编写一个函数,或者一个宏来迭代结构的所有字段并打印它们的偏移量。
If your structure is described with X-Macros, then it is possible to write a function, or a macro to iterate over all the fields of the structure and print their offset.
Gregory Pakosz 的解决方案效果很好。但我遇到了两个小问题:
使用迂腐选项进行编译时,我收到警告:“ISO99 需要使用剩余参数”。
这是由第一个 FOR_EACH_1 宏中的变量参数引起的。删除这些内容并更改 FOR_EACH_2 中对 FOR_EACH_1 的调用可消除此警告。
由于我以非常通用的方式使用它,因此有时我不得不仅使用 1 个参数来调用重复宏。 (我知道重复一个项目 1 次是没有意义的;))。幸运的是,这个问题的解决方案非常简单。只需从 FOR_EACH 宏中删除 x 参数即可。
这是包含两个更改的完整列表:
The solution of Gregory Pakosz worked great. But I had two minor problems with it:
Compiling with the pedantic option I got the warning: "ISO99 requires rest arguments to be used".
This is caused by the variad arguments in the first FOR_EACH_1 macro. Removing those and changing the call to FOR_EACH_1 in FOR_EACH_2 removed this warning.
Since i used it in a very generic way, i sometimes had to call the repeat macro with only 1 argument. (I know it does not make sense to repeat an item 1 times ;)). Fortunately the solution to this problem was quite simple. Just removing the x parameter from the FOR_EACH macro.
Here the complete listing with the two changes:
也许使用可变参数作为数组初始值设定项,并迭代 countof(array)?即 sizeof(array)/sizeof(array[0])。该数组可能是 C99 匿名数组。
我想不出另一种方法来迭代宏的 var-args,因为我不知道如何对每个 var-arg 元素的文本执行任何操作。 var-arg 部分也可能是一个带有逗号的单个参数,据我所知,您可以使用 CPP 对它执行所有操作。
但这是我迭代 var-args 的想法:
Maybe use the varargs as an array initializer, and iterate over countof(array)? i.e. sizeof(array)/sizeof(array[0]). The array could potentially be a C99 anonymous array.
I can't think of another way to iterate over the var-args of a macro, since I don't know how to do anything to the text of each var-arg element. The var-arg part might as well be a single argument that has commas in it, for all you can do to it with CPP, AFAIK.
But here's my idea for iterating over var-args:
这是我能想到的最好的标准 C:
This is the best I can think of, with standard C:
我将其添加为另一个答案。这是使用 C++0x 进行的尝试,使用 g++ 4.5.0 编译
程序打印
但是,使用这种方法时,传递给 lambda 表达式的所有参数都需要具有相同的类型,即上例中的
int
。然而,lambda 允许您捕获如下变量:打印出:
I'm adding this as another answer. Here is a try at doing it with C++0x, compiled with g++ 4.5.0
The program prints
However, with this approach, all the parameters you pass to the lambda expression need to have the same type,
int
in the example above. However, lambdas allow you to capture variables like:which prints out:
要启用空
__VA_ARGS__
,可以使用 GNU 扩展##_VA_ARGS__
https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros。 html
To enable for an empty
__VA_ARGS__
, one can use the GNU extension##_VA_ARGS__
https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
由于 https://stackoverflow.com/a/11994395/1938348 并不是在 GCC 12 的所有情况下都能很好地工作,因此是使用
__VA_OPT__
删除多余逗号的改进版本:工作示例:https://godbolt. org/z/q7nbj7PxY
As https://stackoverflow.com/a/11994395/1938348 do not work well in every case for GCC 12, there is improved version using
__VA_OPT__
to remove superfluous commas:Working example: https://godbolt.org/z/q7nbj7PxY
如果您的目标是
Objective-C
...请查看 Github 上很棒的 KSVarArgs用法示例:
If you are targeting
Objective-C
… check out the AWESOME KSVarArgs on Githubexample usage: