web-dev-qa-db-ja.com

CとC ++のコンパイルの非互換性-型に名前を付けません

サプライヤーのライブラリをC++アプリケーションと組み合わせて使用​​しようとしています。ライブラリの大部分はCに基づいています。これは通常extern "C"オプションの問題ではありませんが、C++コンパイラが受け入れない問題に遭遇しました。

コードを次のサンプルファイルに単純化しました。 header.hは、suppierライブラリからのヘッダーを表し、main.c/cppは私自身のファイルです。私の実際のアプリケーションはC++アプリケーションなので、main.cppで動作するようにします。

header.h(u64 u64;行に注意してください):

#ifndef HEADER_H
#define HEADER_H

#include <stdint.h>

typedef uint64_t u64;

union teststruct {
    u64 u64;
    struct {
        u64 x:32;
        u64 y:32;
    } s;
};

#endif

main.c:

#include <stdio.h>
#include "header.h"

int main() {
    union teststruct a;
    a.u64=5;
    printf("%x\n", a.u64);

    return 0;
}

main.cpp(main.cと同じですが、余分なextern "C"ステートメントがあります):

#include <stdio.h>

extern "C" {
#include "header.h"
}

int main() {
    union teststruct a;
    a.u64=5;
    printf("%x\n", a.u64);

    return 0;
}

次の行を使用してmain.cをコンパイルします

gcc -o test main.c

問題なくコンパイルします。ただし、コマンドでg ++コンパイラを使用してC++バージョンをコンパイルする

g++ -o test main.cpp

次のコンパイラエラーが発生します。

In file included from main.cpp:12:0:
header.h:11:9: error: ‘u64’ does not name a type
         u64 x:32;
         ^
header.h:12:9: error: ‘u64’ does not name a type
         u64 y:32;
         ^

問題は、サプライヤーが型と変数名の両方に同じ名前(u64)を使用したことです。これは、最初は悪い考えのように思えますが、gccは明らかにそれを受け入れます。ライブラリ(つまりheader.h)は非常に大きいため、これを変更したくありません。これはコード内で頻繁に発生し、ときどき更新されます。 g ++がこの組み合わせを受け入れるようにする方法、またはmain.cppを変更してコンパイルする方法はありますか?without header.hを変更しますか?

51
Sander

teststructは、C++のスコープを定義します。修飾ID teststruct::u64を作成できます。そのため、名前ルックアップの言語規則はそのことを考慮しており、クラスおよびユニオンのメンバーが外部スコープの識別子を隠すことを許可しています。 u64 u64;が導入されると、非修飾u64はグローバル::u64を参照できず、メンバーのみが参照できます。そして、メンバーは型ではありません。

Cでは、union teststructはスコープを定義しません。このフィールドはメンバーアクセスでのみ使用できるため、競合は発生しません。そのため、フィールドはファイルスコープタイプ識別子を隠す必要はありません。

私が知る限り、簡単に回避するためにあなたができることは何もありません。このライブラリ(完全に有効なCライブラリ)は、有効なC++ライブラリではありません。変数名としてnewまたはtryを使用した場合と違いはありません。適応させる必要があります。

48
StoryTeller

C++では違法なヘッダーファイルがあるため、C++としてコンパイルされたコードでは#includeできません。ライブラリヘッダーファイルに変更を加えることができない場合(たとえば、ライブラリのサプライヤーに苦情を申し立てるなど)、最も簡単なオプションは、ライブラリの周りにシンC++互換のラッパーを書くことです:

C++コードをCヘッダーから分離するには、Wrapper.hWrapper.cを作成します。.hはC++に含めるのに有効ですが、not include header.h、およびライブラリの相互作用に必要なすべてのタイプと機能を提供します。次に、.c#include "header.h"を実行し、すべての呼び出し(および型を安全に変換するために必要なこと)を実装できます。これは明らかにC++ではなくCとしてコンパイルする必要があります。

39
Max Langhof

前述のCとC++の非互換性のみが原因である場合は、header.hをプログラムでC++互換ヘッダーファイルに変換し、header.hppなどの名前を付けることができます。そして、新しいバージョンを同じ方法で変換できます。

コンパイラエラーは、何をどこで変更する必要があるかをすべて示しています。

header.h:11:9: error: ‘u64’ does not name a type
  1. header.h;を開きます。
  2. 位置11:9を探します。
  3. そこに::を挿入します。
  4. すべてのdoes not name a typeエラーについて繰り返します。

いくつかの文字列処理とそれが完了しました。

PS:CからC++へのコンバーターもそれを行うことができます。

3