仅扩展为其参数的PROTOTYPE宏有什么意义?


82

我有一个头文件,其中包含

#define PROTOTYPE(s) s

这有什么意义呢?似乎它将只是用其自身替换输入。

周围还有其他大量指令,但只有一个指令似乎被检查了是否定义:#ifndef PROTOTYPE。我在HDF4头文件中找到了执行以下操作的位置:#define PROTOTYPE。因此,这些都不能真正解决我的问题。似乎还是没用的。

使用方法如下:

CS_RETCODE clientmsg_callback PROTOTYPE((
CS_CONTEXT * context,
CS_CONNECTION *connection,
CS_CLIENTMSG *clientmsg));

这是使用Sybase Open Client的项目的一部分。clientmsg_callback稍后在这里使用:

ct_callback(context, NULL, CS_SET, CS_CLIENTMSG_CB,
                  (CS_VOID *)clientmsg_callback);

我将从这里开始一个示例程序:

http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc35570.1570/html/clcprgde/clcprgde10.htm

clientmsg_callback稍后实现。我认为该示例最初是考虑到C而不是C ++编写的。也许与它有关?


6
附近是否有#if/ #ifdef/ #ifndef/#else指令的地方可能有不同的定义呢?当在其他宏(尤其是near#或)中使用时,可能会有所不同##。可能只是一种评论风格。没有足够的背景来真正回答。
aschepler

普遍的回答是:因为某人可能有理由要改变PROTOTYPE。如果您发现代码中的奇怪定义似乎无用,请考虑如果有人想方便地更改某些内容,则可能具有灵活性。
Apollys

Answers:


130

早在C语言的早期,就没有原型。函数参数列表位于函数的括号之后,如下所示

square(x)
int x;
{
int y = x * x;
return y;
}

这些天,当然,参数放在括号内:

square(int x)
{
int y = x * x;
return y;
}

注意“ missing”返回类型;C函数曾经隐式地返回int,只有在您需要其他返回类型时,才必须说出它是什么。

函数声明还有另一套规则。K&R C(较旧的版本)中的函数声明没有参数:

int square();

ANSI C中的函数原型具有参数列表:

int square(int x);

在过渡期间,人们使用了古怪的宏,因此他们可以两种方式进行编译:

int square(PROTOTYPE(int x));

#define PROTOTYPE(s)

它将扩展到第一个版本。

#define PROTOTYPE(s) s

它将扩展到第二个。

关于问题代码中的“额外”括号,当参数列表中有多个参数时,需要使用它们。没有它们,宏调用将具有多个参数,因此不会与仅具有一个参数定义的宏匹配:

PROTOTYPE(int x, int y)   // error: too many arguments
PROTOTYPE((int x, int y)) // ok: only one argument (enclosed in parentheses)

10
哇。过去的冲击波。我从事软件的第一批工作之一就是将这些东西从现有的代码库中剥离出来。对Unix的单行文本更改程序数组建立了健康的尊重。
user4581301

15
我不明白这些定义如何工作,#define PROTOTYPE(s)输入如何int x;变成x?看起来好像对我来说是一个空字符串
Ferrybig

3
@Ferrybig-对不起,我很困惑。它的原型是被这样定义的。在K&R C中,原型没有参数,而在ANSI C中,它具有我们常用的参数列表样式。
皮特·贝克尔,

1
这种做法也可以在zlib.hzlib库的标头中看到,并带有以下OF()宏:github.com/madler/zlib/blob/master/zlib.h
Paul Belanger

@PaulBelanger的实际定义在中zconf.h
SS安妮

16

这样的宏将在头文件的原型中使用,以允许这样的操作:

int foo PROTOTYPE((int bar));

如果检测到ANSI C(__STDC__定义为1),它将扩展为:

int foo(int bar);

如果未检测到ANSI C,它将扩展为:

int foo();

这在C标准化之前很常见。

一些图书馆仍然这样做。如果您浏览tcpd.h(如果有),您将看到:

/* someone else may have defined this */
#undef  __P

/* use prototypes if we have an ANSI C compiler or are using C++ */
#if defined(__STDC__) || defined(__cplusplus)
#define __P(args)       args
#else
#define __P(args)       ()
#endif

这很好地解释了。

至于双括号,__P(arg1, arg2)将给出语法错误(将太多的参数传递给宏),而__P((arg1, arg2))将罚款(仅用括号括起来)。

这类似于__extension__((...))GNUC。在非GNU编译器中,仅#define __extension__(unused)提供半便携式代码,因为仅给出了一个“参数”,并用括号括起来。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.