3

我有一个 C++11 应用程序代码使用的 C99 代码实用程序库。一些内联函数以 C99 风格声明,并在翻译单元中显式生成代码,例如:

// buffer.h
inline bool has_remaining(void* obj) {
...
}

// buffer.c
extern inline bool has_remaining(void * obj);

但是,当我尝试has_remaining在 C++ 应用程序中使用时,我在链接时收到有关多个定义的错误。extern "C" 尽管标头保护说明符,g++ 似乎正在实例化库中已经存在的内联代码。

有没有办法强制 g++ 使用这种类型的定义?

看起来如果我#ifdef __cplusplus使用该属性进行外部定义,gnu_inline就会发生正确的事情,但肯定有一种更便携的方法可以使现代 C 头文件与现代 C++ 兼容?

-- 编辑:工作示例 --

缓冲区.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 */

缓冲区.c:

#include "buffer.h"

extern inline bool has_remaining(void const* const obj);

应用程序.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);
}

编译:

$ 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--__gnu_inline__属性确实解决了多个定义的问题。我仍然希望看到一种(更多)可移植方法或一些决定性的推理为什么不存在。

#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);
}
4

3 回答 3

0

C++11 标准状态 (3.2.3),即:

每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的准确定义;无需诊断。定义可以显式出现在程序中,可以在标准或用户定义库中找到,或者(在适当时)隐式定义(参见 12.1、12.4 和 12.8)。内联函数应在使用它的每个翻译单元中定义。

C++ 也知道 extern+inline,但将其理解为“具有外部链接的内联函数应在所有翻译单元中具有相同的地址”(7.1.2)

因此,您使用的 extern+inline 是纯 C99 功能,您必须有足够的内容来制作类似的东西:

#ifdef __cplusplus
#define C99_PROTOTYPE(x)
#else
#define C99_PROTOTYPE(x) x
#endif

并在 buffer.c 中引用:

// buffer.c
C99_PROTOTYPE(extern inline bool has_remaining(void * obj);)

C++11 标头中的内联函数没问题,并且在没有 C99 样式原型的情况下应该可以正常工作。

于 2013-01-17T07:50:09.477 回答
0

使用staticwithinline应该可以解决“多个定义”问题。即使对于无法自行决定不应为“内联”函数生成符号的编译器也是如此。

于 2013-01-18T04:01:45.033 回答
0

这被报告给 gcc: http ://gcc.gnu.org/bugzilla/show_bug.cgi?id=56066 讨论后从这里开始:http: //gcc.gnu.org/ml/gcc-help/2013-01 /msg00152.html

在 linux 上,gcc 为内联函数发出弱符号,而为 extern 内联函数发出强符号。在链接时,弱者被丢弃以支持强者。显然,在 Windows 上,事情的处理方式不同。我对 Windows 没有任何经验,所以我不知道那里会发生什么。

于 2013-01-24T14:46:43.593 回答