Was bringt ein PROTOTYPE-Makro, das sich nur auf seine Argumente erweitert?

82

Ich habe eine Header-Datei, die enthält

#define PROTOTYPE(s) s

Was ist der Sinn davon? Scheint, als würde es nur die Eingabe durch sich selbst ersetzen.

Es gibt Unmengen anderer Richtlinien, aber die einzige, bei der anscheinend eine Peilung nur überprüft wurde, wenn sie definiert ist : #ifndef PROTOTYPE. Ich habe einige Stellen in HDF4-Header-Dateien gefunden, die dies tun : #define PROTOTYPE. Nichts davon klärt meine Frage wirklich. Scheint immer noch ziemlich nutzlos.

So wird es verwendet:

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

Dies ist Teil eines Projekts, das Sybase Open Client verwendet. clientmsg_callback wird später hier verwendet:

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

Ich gehe von hier aus von einem Beispielprogramm ab:

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

clientmsg_callback wird später implementiert. Ich denke, das Beispiel wurde ursprünglich mit Blick auf C anstelle von C ++ geschrieben. Vielleicht hat das etwas damit zu tun?

Charlie Elverson
quelle
6
Gibt es in der Nähe #if/ #ifdef/ #ifndef/ #elseDirektiven, in denen es stattdessen eine andere Definition geben könnte? Es könnte einen Unterschied machen, wenn es in anderen Makros verwendet wird, insbesondere in der Nähe von #oder ##. Es könnte nur für einen Kommentarstil sein. Nicht genug Kontext, um wirklich zu antworten.
Aschepler
Als allgemeine Antwort: weil jemand einen Grund haben könnte, sich ändern zu wollen PROTOTYPE. Wenn Sie seltsame Definitionen im Code sehen, die nutzlos erscheinen, denken Sie über mögliche Flexibilität nach, wenn jemand etwas bequem ändern möchte.
Apollys unterstützt Monica

Antworten:

130

In den alten Tagen von wirklich, wirklich frühem C gab es keinen Prototyp. Funktionsargument Listen kamen nach der Funktion der Klammern, wie folgt :

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

Heutzutage stehen die Argumente natürlich in Klammern:

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

Beachten Sie den "fehlenden" Rückgabetyp. C-Funktionen, die verwendet wurden, um implizit zurückzukehren int, und nur wenn Sie einen anderen Rückgabetyp benötigten, mussten Sie sagen, was es war.

Funktion Erklärungen noch eine weitere Reihe von Regeln hatte. Eine Funktionsdeklaration in K & R C (der alten Version) hatte keine Argumente:

int square();

Und Funktionsprototypen in ANSI C haben eine Liste von Argumenten:

int square(int x);

Während des Übergangs verwendeten die Leute verrückte Makros, um beide Möglichkeiten zu kompilieren:

int square(PROTOTYPE(int x));

Mit

#define PROTOTYPE(s)

das würde auf die erste Version erweitert.

Mit

#define PROTOTYPE(s) s

es würde sich auf die Sekunde ausdehnen.

In Bezug auf die "zusätzlichen" Klammern im Code in der Frage werden sie benötigt, wenn die Argumentliste mehr als ein Argument enthält. Ohne sie hat der Makroaufruf mehr als ein Argument, sodass ein mit nur einem Argument definiertes Makro nicht übereinstimmt:

PROTOTYPE(int x, int y)   // error: too many arguments
PROTOTYPE((int x, int y)) // ok: only one argument (enclosed in parentheses)
Pete Becker
quelle
10
Beeindruckend. Explosion aus der Vergangenheit. Einer meiner ersten Jobs in der Software war das Entfernen dieses Materials aus einer vorhandenen Codebasis. Aufbau eines gesunden Respekts für Unix 'Reihe von einzeiligen Textmutationsprogrammen.
user4581301
15
Ich bin nicht zu verstehen , wie diese definiert arbeiten, wie funktioniert #define PROTOTYPE(s)mit dem Eingang int x;in eingeschaltet wird x? Es sieht so aus, als würde es sich für mich in eine leere Schnur
einwickeln
3
@ Ferrybig - Entschuldigung, ich habe die Dinge verwirrt. Es ist der Prototyp , der auf diese Weise definiert wird. In K & R C hatte ein Prototyp keine Argumente, und in ANSI C hat er den Stil der Argumentliste, den wir gewohnt sind.
Pete Becker
1
Diese Praxis kann auch in der zlib.hKopfzeile aus der zlib-Bibliothek mit dem OF()Makro gesehen werden: github.com/madler/zlib/blob/master/zlib.h
Paul Belanger
@PaulBelanger Die eigentliche Definition ist in zconf.h.
SS Anne
16

Makros wie dieses würden in den Prototypen in der Header-Datei verwendet, um Folgendes zu ermöglichen:

int foo PROTOTYPE((int bar));

Wenn ANSI C erkannt wurde ( __STDC__definiert als 1), würde dies erweitert werden zu:

int foo(int bar);

Wenn ANSI C nicht erkannt wird, wird dies erweitert auf:

int foo();

was üblich war, bevor C standardisiert wurde.

Einige Bibliotheken tun dies immer noch; Wenn Sie nachsehen tcpd.h(wenn Sie es zur Verfügung haben), werden Sie sehen:

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

Das erklärt es gut.

Was die doppelten Klammern betrifft, __P(arg1, arg2)würde dies einen Syntaxfehler ergeben (Übergabe zu vieler Argumente an das Makro), während __P((arg1, arg2))dies in Ordnung wäre (nur eines in Klammern eingeschlossen).

Dies ist ähnlich wie __extension__((...))in GNU C. In Nicht-GNU-Compilern ist es einfach #define __extension__(unused), semi-portablen Code zu haben, da nur ein "Argument" in Klammern angegeben ist.

SS Anne
quelle