20

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?

1
  • 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
    Aug 8, 2012 at 12:59

1 Answer 1

23

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);
4
  • How could the program be compiled WITHOUT the macro definition?
    – user619818
    Aug 7, 2012 at 12:23
  • @user619818 using extern int isdigit(int), for example.
    – ecatmur
    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
    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 functions Mar 15, 2016 at 1:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.