#ifdef management

  • Thread starter Bilgehan.Balban
  • Start date
B

Bilgehan.Balban

Hi,

I've heard somewhere that Plan9 OS did not use #ifdefs in the
preprocessor but only #ifs. The argument was that #ifdefs make code
less readable. Now that when I read linux kernel code, especially for
distinguishing architecture specific code a lot of #ifdef statements
are used. Same applies for eCos, and that one is I think much less
readable due to #ifdefs.

Surely conditional compilation is a necessity and thats why they
couldn't get away without #ifdefs. My question is, how would one manage
conditional compilation best in C, such that the code is more readable.
For example the following is an #ifdef trick used in the linux kernel:

#ifdef CONDITION
void func(void) {

}
#else
void func(void) {
/* Code that actually does something */
}
#endif

This increases the readability of the code, due to the fact that the
call to func() is left untouched regardless of the condition. Do you
know similar #ifdef management tricks? How could one write code with
least #ifdefs and best readability?

Thanks,
Bahadir
 
C

Christian Bau

Hi,

I've heard somewhere that Plan9 OS did not use #ifdefs in the
preprocessor but only #ifs.

Seems you got the answer to your question right there.

#ifdef SOMEIDENTIFIER

is the same as

#if defined (SOMEIDENTIFIER)
 
B

Bilgehan.Balban

Christian said:
Seems you got the answer to your question right there.

#ifdef SOMEIDENTIFIER

is the same as

#if defined (SOMEIDENTIFIER)

Yes but does this add to readability? I believe this is only syntactic
sugar.

Bahadir
 
M

Michael Mair

Yes but does this add to readability? I believe this is only syntactic
sugar.

It is more consistent
#if defined FOO
#elif defined BAR
....
#else
#endif

In addition, you can do things like
#if (defined __STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
(parens added for reading convenience)

So, the #if defined style offers the same functionality and then
some more. If you need this additional functionality, then you
get more consistent code if using the second style.

BTW: I think of #ifdef/#ifndef as syntactic sugar, as it is an
unnecessary shorthand for #if defined/#if !defined...
However, I am not very consistent in that as I like my header guards
the good old way with #ifndef... ;-) -- in this case, it is entirely
sufficient and means "header guards" to me.


Cheers
Michael
 
M

Michael Wojcik

In addition, you can do things like
#if (defined __STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)

I take your general point, but in this specific case the use of the
"defined" operator is redundant. In the constant-expression that
forms a #if condition, identifiers which are not macros will be
replaced with the pp-token 0, so if __STDC_VERSION__ is not defined,
then __STDC_VERSION__ >= 199901L will be false. (C90 6.8.1)
 
M

Michael Mair

Michael said:
I take your general point, but in this specific case the use of the
"defined" operator is redundant. In the constant-expression that
forms a #if condition, identifiers which are not macros will be
replaced with the pp-token 0, so if __STDC_VERSION__ is not defined,
then __STDC_VERSION__ >= 199901L will be false. (C90 6.8.1)

Thank you for the correction (I completely forgot about this one as
I always go the above way). In the case of
#if defined A && A==0
or similar expressions where the second part evaluates to true
if A==0, this makes a difference, though.

Cheers
Michael
 
M

Michael Wojcik

Thank you for the correction (I completely forgot about this one as
I always go the above way). In the case of
#if defined A && A==0
or similar expressions where the second part evaluates to true
if A==0, this makes a difference, though.

Agreed. Also, of course, a simple "#if defined X" is true regardless
of what value X has, and is useful if X may have a non-numeric value.
There are definitely cases where you want the "defined" operator (or
#ifdef).

At any rate, it doesn't generally hurt to have the extraneous check,
though in some cases it may be clearer to leave it out.

--
Michael Wojcik (e-mail address removed)

Maybe, but it can't compete with _SNA Formats_ for intricate plot
twists. "This format is used only when byte 5, bit 1 is set to 1
(i.e., when generalized PIU trace data is included)" - brilliant!
 
B

Bilgehan.Balban

Michael said:
Agreed. Also, of course, a simple "#if defined X" is true regardless
of what value X has, and is useful if X may have a non-numeric value.
There are definitely cases where you want the "defined" operator (or
#ifdef).

At any rate, it doesn't generally hurt to have the extraneous check,
though in some cases it may be clearer to leave it out.

Hi,

Thanks for the replies so far. I have another simple question. I
usually protect #defines with names that has less chance to clash. But
I'm not sure about the preprocessor namespace scope. Is it per file, or
per compilation pass, or how does it work?

Thanks,
Bahadir
 
M

Mark McIntyre

On 11 Nov 2005 06:15:25 -0800, in comp.lang.c ,
I'm not sure about the preprocessor namespace scope. Is it per file, or
per compilation pass, or how does it work?

Standard preprocessor directives are effective from the point at which
they appear, to the end of the translation module they appear in.

Nonstandard directives such as #pragma may have different rules but
thats beyond the scope of CLC.
 
M

Michael Wojcik

Thanks for the replies so far. I have another simple question. I
usually protect #defines with names that has less chance to clash. But
I'm not sure about the preprocessor namespace scope. Is it per file, or
per compilation pass, or how does it work?

Loosely speaking, it's within a file plus the files it includes, plus
the files they include, and so forth. There are also some identifiers
that the standard requires the implementation define at the beginning
of processing, and most (all?) implementations provide some mechanism
for introducing other macros environmentally, such as on the command
line.

Technically, it's everything in what the standard calls a "translation
unit", plus the predefined macro names, plus any other macros
introduced in implementation-specific ways.

The short, approximate answer is "per file", if you include all the
included files in "file".

Note, by the way, that C does not define "compilation pass[es]". It
defines "translation phases", but they are conceptual; how many times
the source, or some intermediate form, is actually scanned is
implementation-dependent.
 
H

hzmonte

Do you know similar #ifdef management tricks? How could one write code with
least #ifdefs and best readability?

There is an article "#ifdef Considered Harmful" by Henry Spencer in
Summer 1992's USENIX. And Greg Kroach-Hartman wrote a piece "Proper
Linux Kernel Coding Style" in Linux Journal (2002) in which he
advocates "No ifdef's in .c code" - well, he gave an example that's
kind of similar to the one given in the original post, except that the
conditional compilation is in the .h file; but I do not understand how
it would work. In GKH's example, if the macro is not defined, both
definitions in the .c and the .h would be in effect and the compiler
gives a warning. I would appreciate it if someone reads that section
of that article and explains it to me.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,133
Latest member
MDACVReview
Top