Turning Prototypes On And Off


C++ requires that function declarations have prototyped parameter lists, but Classic C won't accept prototypes. Code that compiles as both C++ and Classic C must sense which language is compiling the code, and turn the prototypes on and off accordingly. C++ compilers predefine the macro _cplusplus, so

#ifdef _cplusplus
determines the current language.

The simplest way to write a header that is both Classic C and C++ is to write all the function declarations twice - once with an empty parameter list and once with a prototyped parameter list. Select the appropriate declarations by testing _cplusplus, as in

#ifdef __cplusplus
double foo(char *, int);
int bar(char *);
#else
double foo( );
int bar( );
#endif
If you would also like to use prototypes when compiling with Standard C, add a test for the predefined macro _STDC_. You can write the test as

#if defined_cplusplus || \
defined __STDC__
but Classic C compilers might not understand the defined operator. Write the test as

#ifdef __cplusplus
#define PROTOTYPES
#else
#ifdef __STDC__
#define PROTOTYPES
#endif
#endif
To avoid writing each function declaration twice, make each parameter list conditional. Define a macro PROTO as

#ifdef PROTOTYPES
#define PROTO(x) x
#else
#define PROTO(x) ( )
#endif
Then write the function declarations as

double foo PROTO((char *, int));
int bar PROTO((char *));
The extra set of parentheses around each parameter list transforms the comma-separated list of tokens into a single macro argument. Thus, if prototypes are available, then

PROTO((char *, int))
expands to

(char *, int)
Otherwise, it expands to just ( ).

C++ wants you to replace old-style function definition headings like

double foo(s, n)
char *s;
int n;
{
...
with prototype definitions like

double foo(char *s, int n)
{
...
But Classic C won't accept the prototypes. To make the replacement conditional, write the function definition as

#if PROTOTYPES
double foo(char *s, int n)
#else
double foo(s, n) char *s; int n;
#endif
{
...
This heading is admittedly hard to read. Since C++ only issues a warning (not an error) for old-style headings, you may prefer to just live with the warnings.