【问题标题】:C Macros for more complex functions用于更复杂功能的 C 宏
【发布时间】:2011-02-06 20:20:07
【问题描述】:

我见过简单的宏示例,但想知道更复杂的东西,比如 if 语句和重新分配给定变量。像这样更复杂的表达式可以在宏中完成吗?我有一个可以运行数十亿次的函数,所以最好让预处理器把代码扔进去,而不是来回传递变量。

假设我有以下功能:

int foo(int a, int b, int c){  
if (a > 2)  
  c = a;  
if (b > 3)  
  c = b;  

return a + b + c;  
}

我怎样才能把它变成一个宏?

【问题讨论】:

  • 嗯。你到底想做什么?为什么将其设为宏会改变任何事情。
  • 现在没有理由为此使用宏 - 如果调用开销很大,则使用内联函数,但自 C89 以来就不再需要宏,并且存在许多缺点和陷阱。
  • @Paul:宏是在 C 中进行泛型编程的唯一方法。如果 OP 想要一个像 intlongdouble 参数(在任何组合)?
  • @R..:那么 OP 应该在问题中提到这一点;-p 据我所知,“for this”中的“this”不是“通用编程”。跨度>
  • 我同意宏在这里没用。我想我错过了保罗评论中的“为此”。

标签: c macros


【解决方案1】:

请注意,宏与函数调用不同——宏实际上替换了使用它们的 C 源代码,而不是调用和返回——因此可能会出现很多意外行为!你的例子可以做成这样的宏:

#define FOO(a,b,c)((a)+(b)+(((b)>3)?(b):((a)>2)?(a):(c)))

但同样,还有many pitfalls when using complex macros,例如不明确的运算符优先级和重复的自增/自减运算符。

最好听取其他答案的建议并使用替代策略而不是复杂的宏。

【讨论】:

  • @Alexandre:也许您可以发布一个答案,解释为什么按要求回答他的问题是个坏主意?
  • 为什么投反对票?在我看来是正确的。危险与否,他回答了这个问题。
  • @maerics:参数被多次评估(因此,如果您将x++ 传递给a,那么x 将增加3 倍并且您有未定义的行为),并且它无法检测传递的参数类型不正确,原因有两个。
  • @maerics:您在上面定义的宏存在许多问题,例如,您甚至没有在 a、b 和 c 周围加上括号,因此如果其中任何一个是表达式,它将以惊人的方式失败.更不用说副作用、多重评估等了。
  • 我同意。我用谷歌搜索了“宏是邪恶的”,并获得了 12900 次点击。但后来我用谷歌搜索“只要回答这个问题”,结果就超过了 400 万。 :) 但说真的,我同意你们所有人的看法,这是一个坏主意,只是一个严厉的反对票。
【解决方案2】:

简单 - 不要使用宏 - 只需使用内联函数:

__inline int foo(int a, int b, int c)
{  
    if (a > 2)  
        c = a;  
    if (b > 3)  
        c = b;  
    return a + b + c;  
}

【讨论】:

  • 如果你有一个严肃的 C 编译器,或者使用 inline 而不是 __inline。并不是说实际上标记函数 inline 对它是否被一个体面的编译器内联有很大影响,而是内联函数的定义存在于包含调用的 TU 中这一事实。
  • @Steve:确实,__inline 对于 C 代码来说更安全、更便携,但大多数现代/体面的编译器都会识别内联,尽管它可能需要命令行开关才能启用。
  • 取决于您所说的“便携”是什么意思。如果给定的编译器不支持inline,那么谁知道它不支持当前 C 标准的哪些其他部分?如果您想编写可移植回 C89 的代码,那么您不能依赖任何内联函数的工具,最好的办法通常是定义一个 MY_STATIC_INLINE 宏,该宏将在 C99 中定义为 static inline,在纯中定义为 static C89,以及一些涉及 __inline 的编译器特定的东西(如果可用)。
  • __inline 完全不安全;它的使用具有未定义的行为,因为该名称是为实现保留的。 inline 是安全的,因为如果您的编译器是 C99 之前的版本,您可以简单地 #define inline 忽略它,或者 #define inline __inline 使用一些特定于编译器的 __inline 关键字。
  • @R: inline 在 C99 之前的代码中并不完全安全 - 你不能简单地将其#define 去掉,因为在名为 inline 的代码中可能存在现有的函数、变量等。
【解决方案3】:

虽然您可以用宏替换您的函数,但很可能对性能没有影响。任何合理的编译器都会将函数内联移动,如果它认为有帮助的话。

【讨论】:

    【解决方案4】:

    如果它看起来应该是一个函数,那就让它成为一个函数。

    随着时间的推移,编译器技术已经变得足够好,因此您不必担心此类问题。相信你的编译器,你应该没问题。

    【讨论】:

      猜你喜欢
      • 2013-07-19
      • 2017-04-10
      • 1970-01-01
      • 2013-05-09
      • 2010-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-23
      相关资源
      最近更新 更多