extern "C" in library header

W

William Pursell

I debated whether this belongs in comp.lang.c++, and finally decided
that it belongs here, because it really is a C question...

Suppose I have a perfectly friendly, harmless library, libfoo,
that presents a single function declared:
int foo_function(int x);

The world is simple and all the small creatures rejoice in
its simplicity.

Along comes the evil crumudgeon from the neighboing
kingdom who says: your library is not useable by my
people, and we will declare war on you!

Wishing to avert a catastrophe, we sully our beautiful
header somewhat by adding the tatoo of the beast:
#ifdef __cplusplus
extern "C" {
namespace foo {
#endif
and matching closing braces.

For several years, there is peace in the two
kingdoms.

One day, a young prince of the neighboring kingdom
decides that: foo::foo_function( x ) has redundant
foo, and recognizing that his kingdom still has
enough political clout, he declares that all implementations
of libfoo must provide a less redundant interface. And
so our glorious header is disfigured again and ends
up looking like:

#ifndef FOO_HDR
#define FOO_HDR 1

#ifdef __cplusplus
extern "C" {
namespace foo {
#endif /* __cplusplus */



int foo_function(int x);



#ifdef __cplusplus
int function( int x ) { return foo_function( x ); }
} /* namespace foo */
} /* extern "C" */
#endif /* __cplusplus */
#endif /* FOO_HDR */


The questions are:
1) Given that libfoo is a C library, and that foo.h is a
C header file, I find the above code somewhat
hideous. However, it does seem to provide a
fairly clean interface to the C++ programmer.
Is there anything there that will burn my C code?

2) Given that the final #ifdef __cpluplus block
is going to have to define functions for everything
in the library...is it even worth the hassle? After
all, the only thing the evil prince will gain is
the ability to use" foo::function" instead of
"foo::foo_function". But his foo namespace
is still cluttered. I find the definitions in the
header to be a heinous kludge, but as far as
I can tell, it is an accepted technique in that
not-so-far-away land that lies beyond the
water cooler. What think you?
 
R

Richard Heathfield

William Pursell said:

The questions are:
1) Given that libfoo is a C library, and that foo.h is a
C header file, I find the above code somewhat
hideous.
Likewise.

However, it does seem to provide a
fairly clean interface to the C++ programmer.

So would a flamethrower.

My own preferred strategy is based on the following reasoning:

1) this is a C header, so it'll follow C rules, ONLY.
2) if C++ people want to use it, great! If not, who cares?
3) if they need to wrap another header around it, that's fine
by me, but I ain't changing this one.

I find the definitions in the
header to be a heinous kludge, but as far as
I can tell, it is an accepted technique in that
not-so-far-away land that lies beyond the
water cooler. What think you?

I think C++ people have perfectly good techniques for dealing with C
libraries that do not involve modifying those libraries or their
associated headers. And if they haven't, they're not as good at code
re-use as they fondly imagine.
 
C

Charles Bailey

William Pursell said:

I think C++ people have perfectly good techniques for dealing with C
libraries that do not involve modifying those libraries or their
associated headers. And if they haven't, they're not as good at code
re-use as they fondly imagine.

I totally agree, and this wrapping of a 'namespace' around the C
header file is utterly pointless. Worse than that, it's harmful and
misleading.

In the C code the function will be called foo_function regardless of
what 'namespace' the C++ code has pretended that it is in. If the C++
code has a problem with name clashes, then this kludge is not going to
help. Either the C++ code has other functions supposedly called
foo_function which the C++ compiler has mangled into different
namespaces so they don't clash, or it has other extern "C" functions
which really are called foo_function and even if pretending they are
not can be achieved at compile time for the C++ code, it's not going
to be possible to get it to link with all the conflicting definitions
of foo_function.
 
R

Richard Bos

William Pursell said:
#ifndef FOO_HDR
#define FOO_HDR 1

#ifdef __cplusplus
extern "C" {
namespace foo {
#endif /* __cplusplus */



int foo_function(int x);



#ifdef __cplusplus
int function( int x ) { return foo_function( x ); }
} /* namespace foo */
} /* extern "C" */
#endif /* __cplusplus */
#endif /* FOO_HDR */
Bah.

The questions are:
1) Given that libfoo is a C library, and that foo.h is a
C header file, I find the above code somewhat
hideous.

That doesn't even begin to describe it.

Perhaps the best solution would be to have two headers, a foo.h for C,
and a foo.h++ for c++. A slight bit more work, but probably worth it.

Richard
 
R

Roland Pibinger

1) this is a C header, so it'll follow C rules, ONLY.
2) if C++ people want to use it, great! If not, who cares?
3) if they need to wrap another header around it, that's fine
by me, but I ain't changing this one.

You forget that C/C++ is the most common idiom in the region (look eg.
at job advertisements). Moreover, compared to the other macros many C
libraries put into their header files 'extern "C"' is really harmless.
 
A

Army1987

William Pursell said:
I debated whether this belongs in comp.lang.c++, and finally decided
that it belongs here, because it really is a C question...

Suppose I have a perfectly friendly, harmless library, libfoo,
that presents a single function declared:
int foo_function(int x);

The world is simple and all the small creatures rejoice in
its simplicity.

Along comes the evil crumudgeon from the neighboing
kingdom who says: your library is not useable by my
people, and we will declare war on you!

Wishing to avert a catastrophe, we sully our beautiful
header somewhat by adding the tatoo of the beast:
#ifdef __cplusplus
extern "C" {
namespace foo {
#endif
and matching closing braces.

For several years, there is peace in the two
kingdoms.

One day, a young prince of the neighboring kingdom
decides that: foo::foo_function( x ) has redundant
foo, and recognizing that his kingdom still has
enough political clout, he declares that all implementations
of libfoo must provide a less redundant interface. And
so our glorious header is disfigured again and ends
up looking like:

#ifndef FOO_HDR
#define FOO_HDR 1

#ifdef __cplusplus
extern "C" {
namespace foo {
#endif /* __cplusplus */



int foo_function(int x);



#ifdef __cplusplus
int function( int x ) { return foo_function( x ); }
} /* namespace foo */
} /* extern "C" */
#endif /* __cplusplus */
#endif /* FOO_HDR */

*cough* (fx:vomits)

Try this:
#ifdef __cplusplus
extern "C" {
#endif

int foo_function(int x);

#ifdef __cplusplus
} /* extern "C" */
#endif

And explain the foreign prince that foo_function is not a redundant
interface, and that if your people can use it, so can his people.
If his people want to follow their strange tradition of what they
call namespaces, that's their business. But you won't duplicate all
your functions because he doesn't like their name.
If he disagrees, add this to your header:

#ifdef __cplusplus
#include <cstdlib>
#include <cstdio>
int function(int x)
{
int result = foo_function(x);
#ifdef __DEATHSTATION
#if __DEATHSTATION >= 9000
std::free(std::stderr); // cool...
#else /* __DEATHSTATION < 9000 */
#error "You need to upgrade your machine to version 9000."
#endif
#else /* __DEATHSTATION not defined */
#error "This program uses features not available on your "\
"architecture."
#endif
return result;
}
#endif

And all of your problems will be solved, once and for all.
 
K

Keith Thompson

Perhaps the best solution would be to have two headers, a foo.h for C,
and a foo.h++ for c++. A slight bit more work, but probably worth it.

And good luck keeping them synchronized.
 
R

Richard Heathfield

Roland Pibinger said:
You forget that C/C++ is the most common idiom in the region

No, it isn't the most common idiom in any region. Nor was it even
mentioned by the OP.
Moreover, compared to the other macros many C
libraries put into their header files 'extern "C"' is really harmless.

It's still not legal C, so it's off topic here.
 
R

Richard Heathfield

Keith Thompson said:
And good luck keeping them synchronized.

Actually, that's pretty easy, if the <cough> other header is simply a
wrapper, which #includes the C header.
 
D

Dave Vandervies

Roland Pibinger said:

It's still not legal C, so it's off topic here.

This:
--------
#ifdef __cplusplus
extern "C" {
#endif

/*stuff goes here*/

#ifdef __cplusplus
}
#endif
--------
is, I believe, acceptable to every known C implementation, and is
guaranteed to be legal C99, since C99 forbids C implementations from
#defining __cplusplus and as far as I know no known pre-C99 implementation
does so.

Keeping C headers C++-clean (by doing this and avoiding C++ keywords
in the header) is also a perfectly reasonable acknowledgement of the
syntactic similarity of C and C++, and allows C++ code to use the C
code (by #including the header and linking with the compiled code)
with minimal effort on the part of either programmer.


dave
(of course, the way the IDE I use at work gets confused when I use "class"
as an identifier in my C code (even when there's no C++ in sight) is
just inexcusable.)
 
R

Richard Heathfield

Dave Vandervies said:
Roland Pibinger said:

It's still not legal C, so it's off topic here.

This: [reasonable code]
is, I believe, acceptable to every known C implementation, and is
guaranteed to be legal C99, since C99 forbids C implementations from
#defining __cplusplus and as far as I know no known pre-C99
#implementation
does so.

Well, if it will help, we can always write a pre-C99 implementation that
does. :)
Keeping C headers C++-clean (by doing this and avoiding C++ keywords
in the header) is also a perfectly reasonable acknowledgement of the
syntactic similarity of C and C++, and allows C++ code to use the C
code (by #including the header and linking with the compiled code)
with minimal effort on the part of either programmer.

Maybe, maybe not. I still maintain that it's a C++ issue, not a C issue.
FTR, I make no effort whatsoever to make my headers C++-clean. If I
write C++ code that includes C headers, I just... well, what I do in
C++ is off-topic here, but suffice to say that it's really easy, and
doesn't involve tampering with the C headers.
(of course, the way the IDE I use at work gets confused when I use
"class" as an identifier in my C code (even when there's no C++ in
sight) is just inexcusable.)

Visual Studio, at a guess? It does the same for new, which I find mildly
distracting (on the rare occasions that I use VS), since I frequently
use 'new' as an identifier in constructors. (No, not that kind. C
constructors.)
 
A

Army1987

Dave Vandervies said:
dave
(of course, the way the IDE I use at work gets confused when I use "class"
as an identifier in my C code (even when there's no C++ in sight) is
just inexcusable.)

What about MSVC which whenever I write "int main(" suggests me to
complete it with "const int&"?
 
C

CBFalconer

Army1987 said:
What about MSVC which whenever I write "int main(" suggests me
to complete it with "const int&"?

If it does that when invoked as a C compiler (not C++) it is also
in violation of the syntax rules. Sounds like typical MS
sloppiness.
 
R

Richard Heathfield

CBFalconer said:
If it does that when invoked as a C compiler (not C++) it is also
in violation of the syntax rules.

He's talking about the editor's Intellisense capability, not the
compiler. The Microsoft C compiler is actually very good.
 
R

Richard Bos

Keith Thompson said:
And good luck keeping them synchronized.

That's a matter of good program management, a.k.a., in this case,
planning ahead.

Richard
 
K

Keith Thompson

That's a matter of good program management, a.k.a., in this case,
planning ahead.

A better matter of good program management would be to automatically
generate both headers from some common source, so they *can't* get out
of synch.
 
R

Richard Bos

Keith Thompson said:
Keith Thompson said:
(e-mail address removed) (Richard Bos) writes:
[...]
Perhaps the best solution would be to have two headers, a foo.h for C,
and a foo.h++ for c++. A slight bit more work, but probably worth it.

And good luck keeping them synchronized.

That's a matter of good program management, a.k.a., in this case,
planning ahead.

A better matter of good program management would be to automatically
generate both headers from some common source, so they *can't* get out
of synch.

Depends. If this is a single header with a handful of functions, adding
another shackle to the compilation chain that wasn't there before is
probably only going to introduce more places for the process to go
wrong. If you are using a solid, flexible generation tool already to
generate the whole code base from dozens of templates, this is another
job well suited to it. In between, it's in between.

Richard
 

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

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top