为什么某些库例程同时实现为宏? 为什么“va_arg”宏被声明为一个函数(没有“#define”)?

我正在努力用语言清楚地表达出来。 所以让我把它分成几部分。 背景来自Mike Banahan的C书(链接在下面的每个部分提供)。 这是我的问题,作为粗体的要点:

  • 为什么某些库函数同时也实现为宏? 有什么需要? 这是我从书中读到的内容(第9.1.1节) :

最后一点是,许多库例程可以实现为宏,前提是副作用没有问题(如第7章所述)。 标准保证,如果函数通常作为宏实现,则还将提供用于执行相同作业的真实函数。 要使用真实函数,可以使用#undef取消定义宏名称,或将其名称括在括号中,这样可以确保它不会被视为宏:

  • 我们知道, va_start是一个函数还是宏? 书中的以下文字是混乱的根源,因为它暗示着相同的气息,相邻的线条! (第9.9节)

在尝试访问变量参数列表之前,必须调用va_start 。 它被定义为

#include  void va_start(va_list ap, parmN); 

va_start宏初始化ap以供函数va_argva_end随后使用。

  • 最后,最令人困惑的部分。 在下面一行中,清楚地写明了va_arg是一个宏,并继续展示它是如何实现的。 但是如何在没有#define关键字的情况下实现宏,并且返回类型(’type’)也是如此,就好像它是一个函数一样? (第9.9节)

初始化后,可以通过va_arg宏顺序访问提供的参数。 这很奇怪,因为返回的类型由宏的参数决定。 请注意,这不可能作为真正的函数实现,仅作为宏。 它被定义为

 #include  type va_arg(va_list ap, type); 

非常感谢您的回答。 谢谢。

这是两个截然不同的问题。

首先, va_startva_argva_end保证是宏。 va_arg不能是一个函数,因为它的第二个参数是一个类型而不是一个值。

至于为什么一些函数也是宏:因为你想要一个内联调用,使它快速,但你可能也想要获取它的地址并将其放在一个函数指针中:

 int (*function_pointer)(int, FILE *) = &(putc);