I am reading 'The Standard C Library' by PJ Plauger which is really interesting. The book explains not only how to USE the library but also how it is implemented.
I have finished reading the ctype.h
section and in the header the functions are declared as both macros AND functions. For example
int isdigit(int);
but also
#define isdigit(c) (_Ctype[(int)(c)] & _DI)
I don't understand why BOTH are used?
Also, if I try to recreate my own custom ctype
header and implementation, I can only compile successfully if I remove the macro (comment out the define).
This aspect was not really explained in the book. Can someone please explain?
-
There is nothing in the C standard forcing a compiler to implement it as a macro. The macro is most likely a residue from the old days when C didn't have inlining. Though a smart compiler should be able to inline that function if needed, without an explicit inline keyword. So the function-like macro is only there because the compiler was implemented by someone who was not brilliant at making compilers.user29079– user290792012年08月08日 12:59:16 +00:00Commented Aug 8, 2012 at 12:59
1 Answer 1
The macro is (putatively) more efficient, as it doesn't involve a function call. It can be optimised more easily, as it just involves a pointer offset lookup.
The function call allows linking against the same library even if the program was compiled without the macro definition - if it was compiled with a different header, or just with a rogue declaration inside the source file. Should, for example, you have a compiler which has someone's "improved" version of ctype.h that didn't have the macro, the function would still exist at runtime for use.
If we look at the standard:
7.1.4 Use of library functions
Any function declared in a header may be additionally implemented as a function-like macro defined in the header, so if a library function is declared explicitly when its header is included, one of the techniques shown below can be used to ensure the declaration is not affected by such a macro. Any macro definition of a function can be suppressed locally by enclosing the name of the function in parentheses, because the name is then not followed by the left parenthesis that indicates expansion of a macro function name. For the same syntactic reason, it is permitted to take the address of a library function even if it is also defined as a macro.
That means that if you write:
int b = (isdigit)(c);
or
int (*f)(int) = &isdigit;
int b = f(c);
then you are invoking the actual function, not the macro. You can also legally write:
#undef isdigit
int b = isdigit(c);
or (in a source file not having #include <ctype.h>
directly or transitively):
extern int isdigit(int);
int b = isdigit(c);
-
How could the program be compiled WITHOUT the macro definition?user619818– user6198182012年08月07日 12:23:09 +00:00Commented Aug 7, 2012 at 12:23
-
@user619818 using
extern int isdigit(int)
, for example.ecatmur– ecatmur2012年08月07日 12:30:55 +00:00Commented Aug 7, 2012 at 12:30 -
Just so I am clear, you mean user has no #include <whatever> but instead adds int isdigit(int); at top of implementation file. OK, just read through your response properly.user619818– user6198182012年08月07日 13:33:47 +00:00Commented Aug 7, 2012 at 13:33
-
Having a callable function (vs. inlined macro code) also allows other languages like python and perl to interface with those functionstechnosaurus– technosaurus2016年03月15日 01:47:43 +00:00Commented Mar 15, 2016 at 1:47