最有用的用户制作的 C 宏(在 GCC 中,还有 C99)?
您认为哪个 C 宏最有用?我找到了以下一个,我用它在C中进行向量算术:
#define v3_op_v3(x, op, y, z) {z[0]=x[0] op y[0]; \
z[1]=x[1] op y[1]; \
z[2]=x[2] op y[2];}
它的工作原理如下:
v3_op_v3(vectorA, +, vectorB, vectorC);
v3_op_v3(vectorE, *, vectorF, vectorJ);
...
What C macro is in your opinion is the most useful? I have found the following one, which I use to do vector arithmetic in C:
#define v3_op_v3(x, op, y, z) {z[0]=x[0] op y[0]; \
z[1]=x[1] op y[1]; \
z[2]=x[2] op y[2];}
It works like that:
v3_op_v3(vectorA, +, vectorB, vectorC);
v3_op_v3(vectorE, *, vectorF, vectorJ);
...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
当然,还有各种 MIN、MAX、ABS 等。
顺便说一句,请注意,以上这些都不能通过 C 中的函数来实现。PS
我可能会将上面的
IMPLIES
宏单独列出来最有用的。它的主要目的是促进编写更优雅和可读的断言,如And, of course, various MIN, MAX, ABS etc.
Note, BTW, that none of the above can be implemented by a function in C.
P.S. I would probably single out the above
IMPLIES
macro as one of the most useful ones. Its main purpose is to facilitate writing of more elegant and readable assertions, as inC 宏的关键点是正确使用它们。在我看来,有三类(不考虑使用它们只是为了给常量提供描述性名称)
在第一种情况,您的宏将仅存在于您的程序中(通常只是一个文件),因此您可以使用像您发布的那样的宏,该宏不受参数双重评估的保护并使用
{...};< /code>(有潜在危险!)。
在第二种情况下(在第三种情况下更是如此),您需要极其小心,确保宏的行为正确,就好像它们是真正的 C 结构一样。
您从 GCC 发布的宏(最小值和最大值)就是一个例子,它们使用全局变量
_a
和_b
来避免双重评估的风险(如 < code>max(x++,y++)) (好吧,他们使用 GCC 扩展,但概念是相同的)。我喜欢使用宏,它有助于让事情变得更清晰,但它们是一个锋利的工具!也许这就是他们名声如此不好的原因,我认为他们是一个非常有用的工具,如果没有他们的话,C 会更糟糕。
我看到其他人提供了第 2 点的示例(宏作为函数),让我举一个创建新的 C 结构的示例:有限状态机。 (我已经在 SO 上发布了这个,但我似乎无法找到它)
您可以这样使用:
您可以在这个主题上添加变体以获得您需要的 FSM 风格。
有人可能不喜欢这个例子,但我发现它完美地展示了简单的宏如何使您的代码更清晰和更具表现力。
The key point with C macros is to use them properly. In my mind there are three categories (not considering using them just to give descriptive names to constants)
In the first case, your macro will live just within your program (usually just a file) so you can use macros like the one you have posted that is not protected against double evaluation of parameters and uses
{...};
(potentially dangerous!).In the second case (and even more in the third) you need to be extremely careful that your macros behave correctly as if they were real C constructs.
The macro you posted from GCC (min and max) is an example of this, they use the global variables
_a
and_b
to avoid the risk of double evaluation (like inmax(x++,y++)
) (well, they use GCC extensions but the concept is the same).I like using macros where it helps to make things more clear but they are a sharp tool! Probably that's what gave them such a bad reputation, I think they are a very useful tool and C would have been much poorer if they were not present.
I see others have provided examples of point 2 (macros as functions), let me give an example of creating a new C construct: the Finite state machine. (I've already posted this on SO but I can't seem to be able to find it)
that you use this way:
You can add variation on this theme to get the flavour of FSM you need.
Someone may not like this example but I find it perfect to demonstrate how simple macros can make your code more legible and expressive.
C99 中的 for-each 循环:
for-each loop in C99:
如果您需要在不同的上下文中多次定义数据,宏可以帮助您避免多次重新列出相同的内容。
例如,假设您想要定义颜色枚举和枚举到字符串函数,而不是列出所有颜色两次,您可以创建一个颜色文件 (colors.def) :
现在您可以在您的 c 文件中定义枚举和字符串转换函数:
If you need to define data multiple times in different contexts, macros can help you avoid have to relist the same thing multiple times.
For example, lets say you want to define an enum of colors and an enum-to-string function, rather then list all the colors twice, you could create a file of the colors (colors.def):
Now you can in your c file you can define your enum and your string conversion function:
请注意,
"%s::%s(%d)"
和format
之间缺少逗号是故意的。它打印一个带有源位置前缀的格式化字符串。我经常在实时嵌入式系统中工作,所以我还在输出中包含时间戳。Note that the lack of a comma between
"%s::%s(%d)"
andformat
is deliberate. It prints a formatted string with source location prepended. I work in real-time embedded systems so often I also include a timestamp in the output as well.适用于 GCC 的 Foreach 循环,特别是具有 GNU 扩展的 C99。适用于字符串和数组。可以通过将动态分配的数组转换为指向数组的指针,然后取消引用它们来使用它们。
该代码已经过测试,可在 GNU/Linux 上与 GCC、ICC 和 Clang 配合使用。
Lambda 表达式(仅限 GCC)
Foreach loop for GCC, specifically C99 with GNU Extensions. Works with strings and arrays. Dynamically allocated arrays can be used by casting them to a pointer to an array, and then dereferencing them.
This code has been tested to work with GCC, ICC and Clang on GNU/Linux.
Lambda expressions (GCC only)
其他人提到container_of (),但没有对这个非常方便的宏提供解释。假设您有一个如下所示的结构:
现在,如果我们有一个指向 b 的指针,我们可以使用 container_of() 来获取指向 thing< 的指针/strong> 以类型安全的方式:
这对于创建抽象数据结构很有用。例如,您现在可以编写一个如下所示的 slist 实现,而不是采用queue.h 所采用的方法来创建 SLIST(每个操作都有大量疯狂的宏)之类的东西:
这不是疯狂的宏代码。它会在错误时提供良好的编译器行号,并且与调试器配合良好。它也是相当类型安全的,除了结构使用多种类型的情况(例如,如果我们允许下面示例中的struct color位于更多的链接列表上,而不仅仅是颜色) 。
用户现在可以像这样使用您的库:
Someone else mentioned container_of(), but didn't provide an explanation for this really handy macro. Let's say you have a struct that looks like this:
Now if we have a pointer to b, we can use container_of() to get a pointer to thing in a type safe fashion:
This is useful in creating abstract data structures. For example, rather than taking the approach queue.h takes for creating things like SLIST (tons of crazy macros for every operation), you can now write an slist implementation that looks something like this:
Which is not crazy macro code. It will give good compiler line-numbers on errors and works nice with the debugger. It's also fairly typesafe, except for cases where structs use multiple types (eg if we allowed struct color in the below example to be on more linked lists than just the colors one).
Users can now use your library like this:
避免一些容易出错的计数
Save yourself some error prone counting
这个来自linux内核(特定于gcc):
其他答案中缺少另一个:
This one is from linux kernel (gcc specific):
Another missing from other answers:
我也喜欢这个:
讨厌宏的人如何进行公平的浮点比较?
I also like this one:
And how you macros-haters do fair floating-point comparisons?
只是标准的:
但没有什么太漂亮的。
Just the standard ones:
but there's nothing too spiffy there.
找到最接近的大于 x 的 32 位无符号整数。我用它来将数组的大小加倍(即高水位线)。
Find the closest 32bit unsigned integer that is larger than x. I use this to double the size of arrays (i.e. the high-water mark).
也可以像这样多类型最小值和最大值
also multi-type Minimum and Maximum like that
检查浮点 x 是否不是数字:
Checking whether a floating point x is Not A Number:
将字节、单词、双字打包为单词、双字和 qword:
将参数括起来始终是避免扩展副作用的好习惯。
Pack bytes,words,dwords into words,dwords and qwords:
Parenthesizing arguments it's always a good practice to avoid side-effects on expansion.
这个太棒了:
我使用它的方式如下:
This one is awesome:
And I use it like:
我经常使用的一个(极少数)是将参数或变量声明为未使用的宏。需要注意的是,最兼容的解决方案(恕我直言)因编译器而异。
One (of the very few) that I use regularly is a macro to declare an argument or variable as unused. The most compatible solution to note this (IMHO) varies by compiler.
TRUE 和 FALSE 似乎很流行。
TRUE and FALSE seem to be popular.