c++ macros

c++ - ¿Cuál es el punto de una macro de PROTOTIPO que simplemente se expande a sus argumentos?



macros (2)

Tengo un archivo de encabezado que contiene

#define PROTOTYPE(s) s

¿Cuál es el punto de esto? Parece que simplemente reemplazaría la entrada por sí misma.

Hay TONELADAS de otras directivas a su alrededor, pero la única que parece tener algún rumbo acaba de comprobarse si está definida: #ifndef PROTOTYPE . Encontré algunos lugares en los archivos de encabezado HDF4 que hacen esto: #define PROTOTYPE . Entonces, nada de eso realmente aclara mi pregunta. Todavía parece bastante inútil.

Así es como se usa:

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

Esto es parte de un proyecto que usa Sybase Open Client. clientmsg_callback se usa más tarde aquí:

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

Me voy de un programa de muestra desde aquí:

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

clientmsg_callback se implementa más tarde. Creo que la muestra se escribió originalmente con C en mente, en lugar de C ++. ¿Quizás eso tiene algo que ver con eso?


En los viejos tiempos de C muy, muy temprano, no existía un prototipo. Las listas de argumentos de la función llegaron después de los paréntesis de la función, de esta manera :

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

En estos días, por supuesto, los argumentos van entre paréntesis:

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

Tenga en cuenta el tipo de retorno "perdido"; Las funciones C solían devolver implícitamente int , y solo si necesitabas un tipo de retorno diferente tenías que decir qué era.

Las declaraciones de funciones tenían otro conjunto de reglas. Una declaración de función en K&R C (la versión antigua) no tenía argumentos:

int square();

Y los prototipos de funciones en ANSI C tienen una lista de argumentos:

int square(int x);

Durante la transición, las personas usaron macros extravagantes para poder compilar en ambos sentidos:

int square(PROTOTYPE(int x));

Con

#define PROTOTYPE(s)

eso se expandiría a la primera versión.

Con

#define PROTOTYPE(s) s

se expandiría a la segunda.

Con respecto a los paréntesis "adicionales" en el código de la pregunta, son necesarios cuando hay más de un argumento en la lista de argumentos. Sin ellos, la invocación de macro tiene más de un argumento, por lo que no coincidirá con una macro definida con un solo argumento:

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


Macros como este se usarían en los prototipos en el archivo de encabezado para permitir algo como esto:

int foo PROTOTYPE((int bar));

Si se detectó ANSI C ( __STDC__ definido como 1), esto se expandiría a:

int foo(int bar);

Si no se detecta ANSI C, esto se expandiría a:

int foo();

que era común antes de que C fuera estandarizado.

Algunas bibliotecas todavía hacen esto; si busca en tcpd.h (si lo tiene disponible), verá:

/* 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

Esto lo explica bien.

En cuanto a los paréntesis dobles, __P(arg1, arg2) daría un error de sintaxis (pasar demasiados argumentos a la macro), mientras que __P((arg1, arg2)) estaría bien (solo uno entre paréntesis).

Esto es similar a __extension__((...)) en GNU C. En compiladores que no sean GNU, simplemente #define __extension__(unused) para tener un código semi-portátil, ya que solo se da un "argumento", entre paréntesis.