3

C++11アプリケーションコードで使用されるC99コードのユーティリティライブラリがあります。いくつかのインライン関数は、次のように変換ユニットで明示的に生成されたコードを使用してC99スタイルで宣言されます。

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

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

ただし、has_remainingC ++アプリケーションで使用しようとすると、リンク時に複数の定義に関するエラーが発生します。extern "C" ヘッダーガード指定子にもかかわらず、g++はライブラリにすでに存在するインラインコードをインスタンス化しているようです。

g ++にこのタイプの定義を強制的に使用させる方法はありますか?

#ifdef __cplusplus属性を使用した外部定義の場合、正しいことが起こるように見えgnu_inlineますが、最新のCヘッダーを最新のC ++と互換性を保つためのより移植性の高い方法は確かにありますか?

-編集:実例-

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

コンパイル:

$ 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

--編集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

これは 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では、物事の扱いが異なります。私は窓の経験がないので、そこで何が起こるかわかりません。

于 2013-01-24T14:46:43.593 に答える
0

C++11 標準の状態 (3.2.3) では、次のようになります。

すべてのプログラムには、そのプログラムで ODR で使用されるすべての非インライン関数または変数の定義が 1 つだけ含まれている必要があります。診断は必要ありません。定義は、プログラム内で明示的に表示されるか、標準またはユーザー定義ライブラリーで見つけることができます。または (適切な場合) 暗黙的に定義されます (12.1、12.4、および 12.8 を参照)。インライン関数は、odr が使用されるすべての翻訳単位で定義されます。

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

staticwithを使用すると、 inline「複数の定義」の問題が修正されます。「インライン化」された関数のシンボルを生成すべきではないことを独自に決定できないコンパイラであっても。

于 2013-01-18T04:01:45.033 に答える