Mam plik nagłówkowy, który zawiera
#define PROTOTYPE(s) s
Jaki to ma sens? Wygląda na to, że po prostu zastąpiłby wejście sobą.
Istnieje mnóstwo innych dyrektyw wokół niego, ale jedynym, który wydaje się mieć żadnego wpływu po prostu sprawdzić, czy jest zdefiniowana: #ifndef PROTOTYPE
. Znalazłem kilka miejsc w plikach nagłówkowych HDF4 że to zrobić: #define PROTOTYPE
. Więc nic z tego nie wyjaśnia mojego pytania. Wciąż wydaje się całkiem bezużyteczny.
Oto jak to jest używane:
CS_RETCODE clientmsg_callback PROTOTYPE((
CS_CONTEXT * context,
CS_CONNECTION *connection,
CS_CLIENTMSG *clientmsg));
Jest to część projektu korzystającego z Sybase Open Client. clientmsg_callback jest później używany tutaj:
ct_callback(context, NULL, CS_SET, CS_CLIENTMSG_CB,
(CS_VOID *)clientmsg_callback);
Wychodzę z przykładowego programu stąd:
clientmsg_callback jest implementowany później. Myślę, że próbka została pierwotnie napisana z myślą o C, a nie o C ++. Może to ma z tym coś wspólnego?
#if
/#ifdef
/#ifndef
/, w#else
których zamiast tego może mieć inną definicję? Może to mieć znaczenie, gdy jest używane w innych makrach, zwłaszcza w pobliżu#
lub##
. Może to być tylko styl komentowania. Za mało kontekstu, aby naprawdę odpowiedzieć.PROTOTYPE
. Jeśli widzisz w kodzie dziwne definicje, które wydają się bezużyteczne, pomyśl o potencjalnej elastyczności, jeśli ktoś chciałby coś wygodnie zmienić.Odpowiedzi:
W dawnych czasach naprawdę, bardzo wczesnego C, nie było czegoś takiego jak prototyp. Listy argumentów funkcji pojawiają się po nawiasach funkcji, na przykład :
square(x) int x; { int y = x * x; return y; }
Obecnie argumenty są oczywiście umieszczone w nawiasach:
square(int x) { int y = x * x; return y; }
Zwróć uwagę na „brakujący” typ zwrotu; Funkcje C używane do niejawnego zwracania
int
, i tylko wtedy, gdy potrzebny był inny typ zwracania, trzeba było powiedzieć, co to jest.Deklaracje funkcji miały jeszcze inny zestaw reguł. Deklaracja funkcji w K&R C (stara wersja) nie miała argumentów:
int square();
A prototypy funkcji w ANSI C mają listę argumentów:
int square(int x);
Podczas przejścia ludzie używali zwariowanych makr, aby mogli kompilować w obie strony:
int square(PROTOTYPE(int x));
Z
#define PROTOTYPE(s)
która rozwinie się do pierwszej wersji.
Z
#define PROTOTYPE(s) s
rozszerzyłby się do drugiego.
Jeśli chodzi o „dodatkowe” nawiasy w kodzie w pytaniu, są one potrzebne, gdy na liście argumentów jest więcej niż jeden argument. Bez nich wywołanie makra ma więcej niż jeden argument, więc nie dopasuje makra zdefiniowanego tylko z jednym argumentem:
PROTOTYPE(int x, int y) // error: too many arguments PROTOTYPE((int x, int y)) // ok: only one argument (enclosed in parentheses)
źródło
#define PROTOTYPE(s)
z wejściemint x;
zostaje przekształconyx
? Wygląda na to, że zawija się do pustego sznurkazlib.h
nagłówku z biblioteki zlib zOF()
makrem: github.com/madler/zlib/blob/master/zlib.hzconf.h
.Makra takie jak to byłyby używane w prototypach w pliku nagłówkowym, aby umożliwić coś takiego:
int foo PROTOTYPE((int bar));
Gdyby wykryto ANSI C (
__STDC__
zdefiniowane jako 1), rozwinęłoby się to do:int foo(int bar);
Jeśli ANSI C nie zostanie wykryty, rozwinie się do:
int foo();
co było powszechne przed standaryzacją C.
Niektóre biblioteki nadal to robią; jeśli zajrzysz do środka
tcpd.h
(jeśli masz to dostępne), zobaczysz:To dobrze to wyjaśnia.
Jeśli chodzi o podwójne nawiasy,
__P(arg1, arg2)
dałoby błąd składniowy (przekazanie zbyt wielu argumentów do makra), podczas gdy__P((arg1, arg2))
byłoby w porządku (tylko jeden ujęty w nawias).Jest to podobne do
__extension__((...))
GNU C. W kompilatorach innych niż GNU wystarczy#define __extension__(unused)
mieć pół-przenośny kod, ponieważ podany jest tylko jeden „argument” zawinięty w nawiasy.źródło