问题
I have a utility library of C99 code used by C++11 application code. A few inline functions are declared in the C99 style with code explicitly generated in the translation unit like:
// buffer.h
inline bool has_remaining(void* obj) {
...
}
// buffer.c
extern inline bool has_remaining(void * obj);
However, when I try to use has_remaining
in the C++ application, I get errors about multiple definitions at link time. It seems that g++ is instantiating the inline code that already exists in the library, despite the extern "C"
header guards specifier.
Is there a way to coerce g++ into working with this type of definition?
It looks like if I #ifdef __cplusplus
an extern definition with the gnu_inline
attribute, the right thing will happen, but surely there is a more portable way to keep modern C headers compatible with modern C++?
-- Edit: Working Example --
buffer.h:
#ifndef BUFF_H
#define BUFF_H
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
inline bool has_remaining(void const* const obj) {
return (obj != NULL);
}
#ifdef __cplusplus
}
#endif
#endif /* BUFF_H */
buffer.c:
#include "buffer.h"
extern inline bool has_remaining(void const* const obj);
app.cpp:
#include <stdlib.h>
#include <stdio.h>
#include "buffer.h"
int main(int argc, char** argv) {
char const* str = "okay";
printf(str);
has_remaining(str);
return (0);
}
compile:
$ gcc -std=gnu99 -o buffer.o -c buffer.c
$ g++ -std=gnu++11 -o app.o -c app.cpp
$ g++ -Wl,--subsystem,console -o app.exe app.o buffer.o
buffer.o:buffer.c:(.text+0x0): multiple definition of `has_remaining'
app.o:app.cpp:(.text$has_remaining[_has_remaining]+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
--Edit 2--
The __gnu_inline__
attribute does indeed fix the problem of multiple definitions. I'd still like to see a (more) portable approach or some conclusive reasoning why one doesn't exist.
#if defined(__cplusplus) && defined(NOTBROKEN)
#define EXTERN_INLINE extern inline __attribute__((__gnu_inline__))
#else
#define EXTERN_INLINE inline
#endif
EXTERN_INLINE bool has_remaining(void const* const obj) {
return (obj != NULL);
}
回答1:
This was reported to gcc: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56066 after a discussion starting here: http://gcc.gnu.org/ml/gcc-help/2013-01/msg00152.html
On linux, gcc emits weak symbols for the inline functions, and a strong symbol for the extern inline one. At link time, the weak ones are discarded in favor of the strong one. Apparently, on windows, things are handled differently. I don't have any experience with windows, so I can't tell what happens there.
回答2:
C++11 standard states (3.2.3), that:
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is odr-used.
C++ also knows about extern+inline, but understands it as "An inline function with external linkage shall have the same address in all translation units" (7.1.2)
So extern+inline as you are using it is pure C99 feature, and there must be sufficient for you to make something like:
#ifdef __cplusplus
#define C99_PROTOTYPE(x)
#else
#define C99_PROTOTYPE(x) x
#endif
And refer in buffer.c:
// buffer.c
C99_PROTOTYPE(extern inline bool has_remaining(void * obj);)
inline function in header for C++11 is ok and should work fine without C99-style prototypes.
回答3:
Using static
with inline
should fix 'multiple definitions' problem. Even for a compiler which can't decide on its own that it shouldn't generate symbols for 'inline'd functions.
来源:https://stackoverflow.com/questions/14372185/compatible-definitions-of-inline-functions-for-c99-and-c