tags:

views:

186

answers:

3

I have a couple of files written in C, and I want them to be C++-compatible, so for my C headers I use;

#ifdef __cplusplus
extern "C" {
#endif

at the beginning of the file and of course

#ifdef __cplusplus
}
#endif

...at the end. But it seems to create problems with the 'inline' keyword. My solution is to simply remove the inline keyword for C++, but I guess it could have a bad effect on C++ programs (these functions are called gazillions of times).

Is there a better solution ?

A: 

Inline functions are expected to be multiply defined, so:

#ifdef __cplusplus
extern "C" {
#elif __STDC_VERSION__ >= 199901L
   /* do nothing, C99 supports inline */
#else
#  define inline static
#endif

Many C compilers have non-standard extensions to mark functions as inline, you could also define it as __attribute__((always_inline)) (if __GNUC__ is defined)

EDIT: For better and more complete advice, see: http://www.greenend.org.uk/rjk/2003/03/inline.html

Ben Voigt
Firstly, the OP was talking about problems in C++ mode, not in C mode. Secondly, inline functions in C++ have *external* linkage, not "static" (internal?) linkage.
AndreyT
Corrected misinformation about linkage. But C++ inline functions are declared in a header file, so replacing `inline` with `static` actually works rather well.
Ben Voigt
Also the OP can't just remove the keyword `inline` or there'll be multiple definition errors in ALL modes, not just C++.
Ben Voigt
@Ben Voigt: Yes, until you, for example, declare a static variable inside the inline function. As long as the function is just `inline`, that variable will be shared by the entire C++ program. Once you redeclare the function as `static`, each translation unit will get its own instance of the variable. The behavior will obviously change.
AndreyT
Also it is illegal to use #define to replace any of the reserved tokens.
Martin York
@Martin: Right, you'd need to add a test for C99 (and do nothing). But `inline` isn't a reserved token in C89/C90.
Ben Voigt
@Andrey: Use of static variable in inline functions is completely non-portable (http://www.glenmccl.com/ansi_015.htm) Maybe it's a bigger problem than I realize, but I've never had static variables in inline functions so I never tried to make that work. OTOH small functions in header files compiled as both C and C++ I've done many times.
Ben Voigt
@Ben Voigt: I don't understand what you mean by "non-portable". The C++ language defines the behavior with static variables in inline functions, so it is prefectly portable. If you mean that there are old pre-standard compilers that implement a different behavior... well, probably, but I don't think it is a reason to call something "non-portable".
AndreyT
@Andrey: I mean different versions of the standard already had different behavior. If we're assuming the latest version, the whole thing is a non-issue: C99 has `inline`.
Ben Voigt
@AndreyT, if I remember correctly, C99 prohibits static variables inside inline functions.
avakar
Someone also should go fix the wikipedia article (which I didn't write, I found it looking for the C99 version test): http://en.wikipedia.org/wiki/C99#Version_detection
Ben Voigt
Also, avakar is correct. C99 forbids inline functions using modifiable (non-`const`) static variables.
Ben Voigt
Yes, C++ and C99 are different when it comes to inline functions. And it all boils down to which behavior the OP is trying to implement. From the OP's description I'd guess that he's working with C++ and C89/90 combination.
AndreyT
@AndreyT: I'd guess that too, but it could also be C++, C89/C90, AND C99. Or the C compiler could get upgraded in the future. Either of these possibilities rules out static variables in inline functions.
Ben Voigt
@AndreyT: In truth I'm only working with C, not C++. But some collaborators use C++ and it would be handy if my code was C++-compatible.
Shinka
+1  A: 

About every compiler ignores inline since it thinks it knows better (usually it does) - if it's short and called many many times, it will be inlined anyway, so don't worry too much.

delnan
Good comment, but this is not an answer. What should Shinka do in order to make the functions visible to all compilation units so the compiler CAN inline them, without multiple definition errors?
Ben Voigt
This is wrong: first compilers cannot ignore the `inline` keyword, they can just decide not to inline, but the rest of the effects of the keyword --including allowing multiple definitions of the function when linking-- must be performed. Even if you only talk about the actual code inlining, I have seen cases where g++ 4.1 will decide not to inline a method defined in the class definition (implicitly inlined according to the standard) but will inline it if the method was marked inline, I don't have any test case with free functions though.
David Rodríguez - dribeas
+2  A: 

If I understand correctly, I would do:


 #ifdef __cplusplus
 #define D_INLINE static
 extern "C" {
 #else
 #define D_INLINE inline
 #endif

And use the D_INLINE for the functions that I think should need inline. As delnan said, the compiler will optimize it anyway and the inline keyword is just a hint to the compiler that the programmer thinks that the compiler should inline the function. It doesn't force the compiler to inline the function.

Simon
You're going to get multiple definition errors all over the place. Plus the logic is backward: It's C++ that supports the `inline` keyword and C89/C90 that don't.
Ben Voigt
Well it seems to work. Anyway, to be fair, all the C and C++ compilers I'm interested in support the 'inline' keyword. I think the problem is that, with C++, I need to add "extern" and it causes conflicts with the inline keyword.
Shinka
In standard C++03, `inline` functions are automatically `extern`. Does it work without `extern`?
Ben Voigt
@Ben Voigt, I'm not sure I understand why there would be multiple definition errors. I've tried it out and it seems to work pretty well. Could you please care to explain why?
Simon
The definition of any inline function is in a header file. That header file is included in multiple compilation units. Having a definition of the same identifier in multiple compilation units without causing internal linkage with either `inline` or `static` causes linker errors.
Ben Voigt
Ah that is correct. My bad. Edited the post to fix that.
Simon
But the compiler will throw an error, saying the function was decladed extern, and then static. It seems the best is to use #ifndef D_INLINE #define D_INLINE #endif
Shinka