为什么C宏不是类型安全的?

Sar*_*ien 22 c c++ macros types

如果遇到了这种说法 时间并不能弄清楚什么是应该的意思.由于生成的代码是使用常规C编译器编译的,因此最终会像任何其他代码一样(或很少)检查类型.

那么为什么宏不安全呢?这似乎是他们应被视为邪恶的主要原因之一.

Vic*_*cky 39

考虑典型的"最大"宏,与功能:

#define MAX(a,b) a < b ? a : b
int max(int a, int b) {return a < b ? a : b;}
Run Code Online (Sandbox Code Playgroud)

当人们说宏在函数的方式不是类型安全时,这就是人们的意思:

如果函数的调用者写入

char *foo = max("abc","def");
Run Code Online (Sandbox Code Playgroud)

编译器会发出警告.

然而,如果宏的调用者写道:

char *foo = MAX("abc", "def");
Run Code Online (Sandbox Code Playgroud)

预处理器将替换为:

char *foo = "abc" < "def" ? "abc" : "def";
Run Code Online (Sandbox Code Playgroud)

这将编译没有问题,但几乎肯定不会给你想要的结果.

另外当然副作用也不同,请考虑功能案例:

int x = 1, y = 2;
int a = max(x++,y++); 
Run Code Online (Sandbox Code Playgroud)

max()函数将对x和y的原始值进行操作,后递增将在函数返回后生效.

在宏案例中:

int x = 1, y = 2;
int b = MAX(x++,y++);
Run Code Online (Sandbox Code Playgroud)

第二行被预处理给出:

int b = x++ < y++ ? x++ : y++;
Run Code Online (Sandbox Code Playgroud)

同样,没有编译器警告或错误,但不会是您期望的行为.

  • 通过此示例,模板也不是类型安全的.模板化的"max"函数将允许完全相同的指针比较行为.当然,模板不会成为多重评估问题的牺牲品. (10认同)
  • @Joel:这个答案的要点是函数(模板)可以为特定的参数类型重载(或专用),而宏只有一个实现,无论参数类型如何. (2认同)
  • 这是关于宏的好想法,但不是问题的答案,不是吗? (2认同)
  • 我在这里遗漏了什么,或者你最大的宏/函数是否返回两个参数中较低的一个? (2认同)

mar*_*ark 11

好吧,他们不是直接类型安全的...我想在某些场景/用法中你可以说他们可以间接(即结果代码)类型安全.但你当然可以创建一个用于整数的宏并传递它的字符串...处理宏的预处理器当然不关心.编译器可能会阻塞它,具体取决于使用情况......

  • 这听起来不错,但是有人应该向世界指出,这不会使宏以任何方式产生邪恶,否则必须重复.:) (5认同)
  • 我曾经在一个核心头文件之一的项目中工作,其中一个同事#define'd printf是别的东西. (3认同)

Tom*_*ner 11

宏不是类型安全的,因为它们不了解类型.

你不能告诉宏只采取整数.预处理器识别宏用法,它用一组令牌替换一个令牌序列(带有参数的宏).如果使用正确,这是一个强大的工具,但它很容易使用不正确.

使用函数,您可以定义一个函数void f(int, int),如果您尝试使用f的返回值或传递字符串,编译器将标记.

用宏 - 没有机会.唯一的检查是给出正确数量的参数.然后它适当地替换令牌并传递给编译器.

#define F(A, B)
Run Code Online (Sandbox Code Playgroud)

允许你打电话F(1, 2),F("A", 2)或者F(1, (2, 3, 4))或者......

如果宏中的某些内容需要某种类型的安全性,您可能会从编译器中获得错误,或者您可能不会收到错误.但这不是预处理器.

将字符串传递给期望数字的宏时,您可以获得一些非常奇怪的结果,因为您最终可能会使用字符串地址作为数字而不会从编译器发出吱吱声.