Make Q's

Joshua Judson Rosen rozzin at geekspace.com
Fri Sep 18 15:17:52 EDT 2009


bruce.labitt at autoliv.com writes:
>
> gnhlug-discuss-bounces at mail.gnhlug.org wrote on 09/18/2009 12:16:15 PM:
> > 
> > Derek Atkins writes:
> > 
> > > Perhaps you need an 'extern "C"' in there so C++ knows how to
> > > call the C functions?
> > 
> > To cut to the chase, Bruce probably should make sure that all of his C
> > functions are declared in C-specific header files that have the
> > following pattern:
> > 
> > #ifndef UTIL_H
> > #define UTIL_H
> > 
> > #ifdef __cplusplus
> > extern "C" {
> > #endif
> > 
> > void some_function_with_c_linkage();
> > 
> > #ifdef __cplusplus
> > }
> > #endif
> > 
> > #endif  /* UTIL_H */
> 
> Could you explain why this is necessary, and what it does?  What is 
> necessary to use this?

There are actually two distinct things going on, here:

* The multiple-#include guard:
      #ifndef UTIL_H
      #define UTIL_H
      [...stuff you actually care about ...]
      #endif"

This makes it safe for a given header to be `#include'd multiple
times in the same file, which can become a common occurrence if
someone puts an "#include <yourfile.h>" directive into another
header-file, which may in turn be `#include'd by other headers-files.

Without this guard, multiple successive `#include's of your
header would effectively result in the contained definitions
being written multiple times, which may make your compiler throw a
`X is multiply defined' error.


* The `extern "C" {...}' C++ linkage guard:

This is actually C++ code, which tells the C++ compiler to avoid
mangling the names of functions/variables/constants used in the
code that it's compiling; "mangling" is, in fact, a technical
term. Here's a Wikipedia article on it:

    http://en.wikipedia.org/wiki/Name_mangling

The "#ifdef __cplusplus" is using a condition that will be true if the
code is being compiled by a C++ compiler ("__cplusplus" will be defined),
and should be false otherwise.

Some people consider this `embedding C++ code that is normally
filtered-out by the preprocessor' trick as being an ugly hack
that would more rightly be handled by the people trying to use
the C library from C++, and may even say that the right way
of consuming a C library from C++ is to write an opaque shim
C++ library.

Others `suck it up and do the polite thing' (this is the `opinion'
aspect of Kevin's recommendation), bending to the facts that there are
a lot of C++ programmers who think that C++ compilers can `also just
compile C code', and the fact that writing an opaque shim /is/
actually some amount of work.

In reality, C++ *is* `backward compatible with C'... to some extent,
but in a way that's technical and pedantic enough that `backward
compatible with C' doesn't mean what most people would naively
interpret it as meaning (this is the `inflexible "you must do this if
you want this to work"' part).

You should also avoid using the word "class" in your C headers
(do not be tempted into naming a struct-member "class", for example),
because C++ compilers will likely fail when they see it in a context
that looks nonsensical to them, even if it *is* wrapped in an `extern "C"'
construct. There are probably some other things of which you should be wary
when writing C headers for use in C++ programs, but the the above issues
are the big ones.

-- 
Don't be afraid to ask (Lf.((Lx.xx) (Lr.f(rr)))).


More information about the gnhlug-discuss mailing list