【问题标题】:How do function renaming macros work, and should one use them?函数重命名宏是如何工作的,应该使用它们吗?
【发布时间】:2022-09-27 23:10:36
【问题描述】:

每个人都知道经典的#define DEFAULT_VALUE 100 宏,其中预处理器只会找到“令牌”并将其替换为任何值。

我遇到的问题是理解这个#define my_puts(x) puts(x) 的功能版本。我面前有 K&R,但我根本找不到合适的解释。例如:

  • 为什么我需要提供参数的数量?
  • 为什么他们的名字可以是什么?
  • 为什么我不必提供类型?

但主要是我想知道这个替换是如何在幕后发挥作用的。

在我的脑海里,我想我记得有人在某处说这很糟糕,因为没有类型。

简而言之,我想知道使用宏重命名函数是否安全可靠(而不是手动将函数包装在另一个函数中)。

谢谢!

  • 你问为什么#define my_puts(x) puts(x) 而不是#define my_puts puts
  • 一个常见的例子是在进行网络编程时,并希望在 Windows 和 e.g. Linux。在 Linux 上关闭网络连接的函数是 close,在 Windows 上是 closesocket。它们都采用“socket”参数,所以为了便携,可以使用条件编译定义像my_close_socket 这样的宏,它使用closeclosesocket,具体取决于系统。
  • 也可能存在标准函数接受 X 参数的情况,但程序只会使用 X - n 参数,其余的都是一些默认值。然后可以创建一个只接受X - n 参数的宏,它扩展为传递所有\'X\' 参数的真实函数。
  • 除了这些情况,这种宏几乎没有什么原因。
  • 您是否搜索过“类似函数的 C 宏”?应该有很多解释......无论如何,预处理器与 C 编译器是不同的野兽。因此,它对数据类型一无所知。

标签: c


【解决方案1】:

我遇到的问题是理解这个#define my_puts(x) puts(x) 的功能版本。

您的部分困惑可能源于将此变体视为“函数重命名”宏。一个更传统的术语是“类函数”,指的是形式宏定义和用法。为函数名称提供别名或从一个函数名称转换为另一个函数名称是这种宏的相对较小的用途。

这样的宏更一般地被认为是更好的,简单地作为接受参数的宏。从这个角度来看,您的具体问题有相对明确的答案:

  • 为什么我需要提供参数的数量?

您主要是关联参数名字与宏的参数列表中的各个位置。这是必要的,以便预处理器可以正确扩展宏。从而传递参数的数量(可变参数宏除外)是次要的。

  • 为什么他们的名字可以是什么?

“随便”有点太强了,但答案是宏参数的名称只有在宏定义的范围内才有意义。每当扩展宏时,预处理器将实际参数替换为每个扩展中的参数名称。这类似于善意实际上,函数,所以我不确定为什么会出现这种特殊的不确定性。

  • 为什么我不必提供类型?

宏的?因为就宏具有类型而言,它们都具有相同的类型。它们都扩展为零个或多个标记的序列。您可以将其视为源到源的翻译。生成的令牌序列将由编译器在该过程的后续阶段进行解释。

但主要是我想知道这个替换是如何在幕后发挥作用的。

粗略地说,在源代码中出现范围内函数(如宏)的名称后跟带括号的参数列表的任何地方,宏名称和参数列表被宏的扩展替换,宏参数被适当地替换。

例如,考虑这个类似函数的宏,您可能会在实际源代码中看到它:

#define MIN(x, y) (((x) <= (y)) ? (x) : (y))

在该定义的范围内,此代码...

n = MIN(10, z);

... 扩展为

n = (((10) <= (z)) ? (10) : (z));

请注意,

  • 在这种情况下,类函数宏不提供函数别名。
  • 宏参数被替换到宏扩展中,只要它们在宏定义的替换文本中显示为完整的标记。

在我的脑海里,我想我记得有人在某处说这很糟糕,因为没有类型。

好吧,宏定义中没有声明类型。这并不妨碍所有围绕数据类型的正常规则应用于预处理阶段产生的源代码。这两个因素都需要考虑。在某些方面,上述示例中的MIN() 宏比任何一个函数都更灵活。那不好吗?我并不是要否认有反对的论据,但这是一个多方面的问题,不能通过单一考虑或简单的“好”来很好地捕捉到对比. “差”的评价。

简而言之,我想知道使用宏重命名函数是否安全可靠(而不是手动将函数包装在另一个函数中)。

这在很大程度上与上述任何问题都不同。类函数宏的语义是明确定义的。没有固有安全或安保问题。但是类似函数的宏确实会掩盖正在发生的事情,从而使分析代码变得更加困难。因此,这主要是一个风格问题。

如今,类似函数的宏确实受到了批评,尤其是在 C++ 社区中。在大多数情况下,它们几乎没有什么可以将自己区分为优于功能的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 2016-07-20
    • 1970-01-01
    • 2011-12-18
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多