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

时间:2019-09-03 21:47:53

标签: c++ macros

我有一个包含的头文件

#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 ++编写的。也许与它有关?

2 个答案:

答案 0 :(得分:129)

在真正非常早期的C时代,还没有原型。函数参数列表位于函数括号like this之后:

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

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

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

请注意“缺少”返回类型; 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)

答案 1 :(得分:15)

在头文件的原型中将使用类似这样的宏,以允许这样的事情:

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))会很好(仅括在括号中)。

这类似于GNU C中的__extension__((...))。在非GNU编译器中,只需#define __extension__(unused)具有半便携式代码,只需给出一个“参数”,并用括号括起来即可。