Dlaczego biblioteka C używa makr i funkcji o tej samej nazwie?

20

Czytam „Standardową bibliotekę C” PJ Plaugera, co jest naprawdę interesujące. Książka wyjaśnia nie tylko, jak KORZYSTAĆ z biblioteki, ale także sposób jej implementacji.

Skończyłem czytać ctype.hsekcję, aw nagłówku funkcje są zadeklarowane zarówno jako makra ORAZ funkcje. Na przykład

int isdigit(int);

ale również

#define isdigit(c) (_Ctype[(int)(c)] & _DI)

Nie rozumiem, dlaczego OBU używane są?

Ponadto, jeśli spróbuję odtworzyć własny niestandardowy ctypenagłówek i implementację, mogę pomyślnie skompilować tylko po usunięciu makra (skomentuj definicję).

Ten aspekt nie został tak naprawdę wyjaśniony w książce. Czy ktoś może wyjaśnić?

użytkownik619818
źródło
W standardzie C nic nie zmusza kompilatora do implementacji go jako makra. Makro jest najprawdopodobniej pozostałością po dawnych czasach, kiedy C nie miał inlinii. Chociaż inteligentny kompilator powinien być w stanie wstawić tę funkcję w razie potrzeby, bez wyraźnego słowa kluczowego. Tak więc makro funkcyjne istnieje tylko dlatego, że kompilator został zaimplementowany przez kogoś, kto nie był genialny w tworzeniu kompilatorów.

Odpowiedzi:

23

Makro jest (przypuszczalnie) bardziej wydajne, ponieważ nie wymaga wywołania funkcji. Można go łatwiej zoptymalizować, ponieważ wymaga tylko wyszukiwania przesunięcia wskaźnika.

Wywołanie funkcji pozwala na połączenie z tą samą biblioteką, nawet jeśli program został skompilowany bez definicji makra - jeśli został skompilowany z innym nagłówkiem lub tylko z nieuczciwą deklaracją w pliku źródłowym. Jeśli, na przykład, masz kompilator, który ma czyjąś „ulepszoną” wersję ctype.h, która nie ma makra, funkcja nadal istniałaby w czasie wykonywania do użycia.

Jeśli spojrzymy na standard:

7.1.4 Korzystanie z funkcji bibliotecznych

Każda funkcja zadeklarowana w nagłówku może być dodatkowo zaimplementowana jako makro funkcyjne zdefiniowane w nagłówku, więc jeśli funkcja biblioteki zostanie zadeklarowana jawnie, gdy jej nagłówek jest uwzględniony, można zastosować jedną z technik pokazanych poniżej, aby upewnić się, że deklaracja nie jest dotknięte przez takie makro. Wszelkie definicje makr funkcji można lokalnie pominąć, umieszczając nazwę funkcji w nawiasach, ponieważ po nazwie nie występuje lewy nawias, który wskazuje na rozwinięcie nazwy funkcji makra. Z tego samego powodu składniowego dozwolone jest przyjmowanie adresu funkcji biblioteki, nawet jeśli jest ona również zdefiniowana jako makro.

Oznacza to, że jeśli napiszesz:

int b = (isdigit)(c);

lub

int (*f)(int) = &isdigit;
int b = f(c);

następnie wywołujesz rzeczywistą funkcję, a nie makro. Możesz również legalnie napisać:

#undef isdigit
int b = isdigit(c);

lub (w pliku źródłowym nieposiadającym #include <ctype.h>bezpośrednio ani przejściowo):

extern int isdigit(int);
int b = isdigit(c);
ecatmur
źródło
Jak można skompilować program BEZ definicji makra?
user619818,
@ user619818 przy użyciu extern int isdigit(int), na przykład.
ecatmur
Jasne jest, że użytkownik nie ma #include <cokolwiek>, ale zamiast tego dodaje int isdigit (int); u góry pliku implementacji. OK, po prostu przeczytaj dokładnie swoją odpowiedź.
user619818,
Posiadanie funkcji wywoływalnej (w przeciwieństwie do wbudowanego kodu makr) pozwala również innym językom, takim jak Python i Perl, na
komunikowanie się