在之前的一个问题中,我认为一个好的答案被推荐用于建议使用宏
#define radian2degree(a) (a * 57.295779513082)
#define degree2radian(a) (a * 0.017453292519)
Run Code Online (Sandbox Code Playgroud)
而不是内联函数.请原谅新手问题,但在这种情况下,宏的错误是什么?
大多数其他答案讨论了为什么宏是邪恶的,包括你的例子如何有一个共同的宏使用漏洞.这是Stroustrup的观点:http://www.research.att.com/~bs/bs_faq2.html#macro
但你的问题是询问哪些宏仍然有用.有些东西的宏比内联函数要好,而且你正在做的事情就是用内联函数完成的,例如:
assert()
)offsetof()
使用类型名创建一个强制转换操作的使用次数)但是,如果使用具有内联函数的语言,则不必使用宏的更常见用法.当我处理不支持内联函数的C编译器时,我甚至不愿意使用宏.如果可能的话,我尽量不使用它们来创建类型无关的功能(创建几个带有类型指示符的函数作为名称的一部分).
我也转而使用枚举来命名数字常量而不是#define
.
对于这个特定的宏,如果我使用它如下:
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)
这是预期的结果.
这些只是虚假行为和误用宏可能具有的几个例子.
编辑
你可以在这里看到关于这个的更多讨论
关于宏有几个严格的邪恶的东西.
它们是文本处理,并没有作用域.如果您#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
在某个内部范围内编写函数的人,确信该定义在其自己的范围内有效.