什么时候应该使用宏而不是内联函数?

sem*_*maj 12 c macros inline

在之前的一个问题中,我认为一个好的答案被推荐用于建议使用宏

#define radian2degree(a) (a * 57.295779513082)
#define degree2radian(a) (a * 0.017453292519)
Run Code Online (Sandbox Code Playgroud)

而不是内联函数.请原谅新手问题,但在这种情况下,宏的错误是什么?

Mic*_*urr 8

大多数其他答案讨论了为什么宏是邪恶的,包括你的例子如何有一个共同的宏使用漏洞.这是Stroustrup的观点:http://www.research.att.com/~bs/bs_faq2.html#macro

但你的问题是询问哪些宏仍然有用.有些东西的宏比内联函数要好,而且你正在做的事情就是用内联函数完成的,例如:

  • 象征性粘贴
  • 处理行号等(如创建错误消息assert())
  • 处理不是表达式的事物(例如,offsetof()使用类型名创建一个强制转换操作的使用次数)
  • 宏来获取数组元素的数量(不能用函数来做,因为数组名称太容易衰减到指针)
  • 在C中创建'类型多态'函数式的东西,其中模板不可用

但是,如果使用具有内联函数的语言,则不必使用宏的更常见用法.当我处理不支持内联函数的C编译器时,我甚至不愿意使用宏.如果可能的话,我尽量不使用它们来创建类型无关的功能(创建几个带有类型指示符的函数作为名称的一部分).

我也转而使用枚举来命名数字常量而不是#define.


Ami*_*shk 7

对于这个特定的宏,如果我使用它如下:

int x=1;
x = radian2degree(x);
float y=1;
y = radian2degree(y);
Run Code Online (Sandbox Code Playgroud)

没有类型检查,x,y将包含不同的值.

此外,以下代码

float x=1, y=2;
float z = radian2degree(x+y);
Run Code Online (Sandbox Code Playgroud)

不会做你想的,因为它会转化为

float z = x+y*0.017453292519;
Run Code Online (Sandbox Code Playgroud)

代替

float z = (x+y)+0.017453292519;
Run Code Online (Sandbox Code Playgroud)

这是预期的结果.

这些只是虚假行为和误用宏可能具有的几个例子.

编辑

你可以在这里看到关于这个的更多讨论

  • 好答案.还值得一提的是命名空间污染(例如,我不能再声明一个名为`radian2degree`的局部变量或结构域). (3认同)

Dav*_*ley 7

关于宏有几个严格的邪恶的东西.

它们是文本处理,并没有作用域.如果您#define foo 1,那么任何后续使用foo作为标识符将失败.这可能导致奇怪的编译错误和难以发现的运行时错误.

他们不会在正常意义上接受论证.您可以编写一个函数,它将获取两个int值并返回最大值,因为参数将被计算一次,之后使用的值.你不能写一个宏来做那个,因为它会评估至少一个参数两次,并失败的类似max(x++, --y).

还有一些常见的陷阱.很难在其中获得多个陈述,并且它们需要许多可能多余的括号.

在您的情况下,您需要括号:

#define radian2degree(a) (a * 57.295779513082)
Run Code Online (Sandbox Code Playgroud)

需要是

#define radian2degree(a) ((a) * 57.295779513082)
Run Code Online (Sandbox Code Playgroud)

并且你仍然踩着任何radian2degree在某个内部范围内编写函数的人,确信该定义在其自己的范围内有效.

  • "特征X是邪恶的"并不意味着"不使用特征X",我并不是说宏本身就是邪恶的.全封闭公约很有价值,但并不能解决所有问题.与严格的括号和其他技巧相同.如果可能的话,我建议避免使用类似函数的宏,因为通常有更好的方法来做你想做的事情. (5认同)
  • 我总觉得"功能'x'的陈述是邪恶的,永远不会使用它"似乎暗示程序员是非常愚蠢的.建议以使用时将自身标识为宏的方式命名宏:RADIAN2DEGREEmac或类似的. (2认同)