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

What's the point of a PROTOTYPE macro that merely expands to its arguments?

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

#define PROTOTYPE(s) s

这样做有什么意义?似乎它只会用自己替换输入。

它周围有大量其他指令,但唯一似乎有任何意义的指令只是检查它是否已定义:#ifndef PROTOTYPE。我在 HDF4 头文件中找到了一些这样做的地方:#define PROTOTYPE。所以,none 确实解决了我的问题。好像还是很没用。

使用方法如下:

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++。也许这与它有关?

在非常非常早的 C 时代,还没有原型这样的东西。函数参数列表在函数的括号之后,like this:

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

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

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

注意 "missing" return 类型; C 函数过去常常隐式 return int,只有当您需要不同的 return 类型时,您才必须说出它是什么。

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

int square();

ANSI C 中的函数 prototypes 有一个参数列表:

int square(int x);

在转换期间,人们使用了古怪的宏,以便他们可以两种方式进行编译:

int square(PROTOTYPE(int x));

#define PROTOTYPE(s)

这将扩展到第一个版本。

#define PROTOTYPE(s) s

它会扩展到秒。

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

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

像这样的宏将用于头文件中的原型以允许这样的事情:

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) 即可获得半可移植代码,因为只给出一个 "argument",包装在括号。