web-dev-qa-db-ja.com

C対C ++のTypedef構造体

これにより、C++ではエラーが発生しますが、Cではエラーが発生しません。

typedef struct nodes
{
    int data;
    struct node *next;
}node;

C++では次のエラーが発生します。

/home/DS cpp/linkedlist.cpp|10|error: conflicting declaration ‘typedef struct nodes node’|
/home/DS cpp/linkedlist.cpp|9|error: ‘struct node’ has a previous declaration as ‘struct node’|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

C++で動作させるには、次のように変更する必要があります。

typedef struct node
{
    int data;
    struct node *next;
}node;

私はこれがなぜ起こるか理解していません、私はそれを理解できるようにCとC++の両方で実行の順序を知りたいです。

18
Achyut Rastogi

コードを少し分析してみましょう。

typedef struct nodes
{
    int data;
    struct node *next;
}node;

これは、2つのメンバーを持つ型struct nodesを宣言および定義し、nodeとしてのみ参照できるように型エイリアスを宣言します。

現在、C++では、メンバー宣言struct node *nextnodeと呼ばれる型を自動的に前方宣言します 。それはあなたのtypedefターゲットnodeと衝突します:2つの型に同じ名前を与えようとしているようです。

Cでは、nodeと呼ばれる型は実際にはstruct nodeとのみ呼ばれるため、競合はありません。

2番目のスニペットが機能したのは、メンバー宣言の解析中にstruct nodeがすでに存在するため、そこに新しい型は前方宣言されていないためです。そして、同じtypedefステートメント、C++はまったく気にせず、すべて同じタイプであることを知っている(struct TisT;違い名前ではなく構文にあります)。

[C++11: 7.1.3/3]:指定された非クラススコープでは、typedef指定子を使用して、そのスコープで宣言されている任意の型の名前を再定義し、既に参照している型を参照できます。 [例:

typedef struct s { / ... / } s;
typedef int I;
typedef int I;
typedef I I;

—例の終了]

[C++11: 7.1.3/6]:特定のスコープでは、typedef指定子を使用して、そのスコープで宣言された型の名前を再定義して、異なる型を参照しないでください。 [例:

class complex { / ... / };
typedef int complex; // error: redefinition

—例の終了]

もちろん、C++では、これはすべて意味がないので、次のように記述する必要があります。

struct node
{
   int data;
   node* next;
};

typedef--elaborated-type-specifierstructを離れる必要はありません。

指定したCの例はエラーになります。 struct nodeで定義していないタグ名(node)を使用しています。

これら2つの選択肢がある場合、2番目の選択肢が使用されます。私は少し経済を好む:

typedef struct node_t
{
    int data;
    struct node_t *next;
} node_t;

CまたはC++では、タグ名には独自の名前空間があるため、タグとtypedef名に同じ名前を使用しても問題はありません。 Cでは、これにより、node_tまたはstruct node_tのいずれかを使用して、この構造体型を参照できます。 C++は、宣言されたタイプ名が存在しない場合、タグ名からタイプ名を検索します。したがって、上記の二重定義は必要ありませんが、害はありません。

どちらの言語でも、型が完全に定義される前の任意の時点で明示的なstruct node_tバージョンが必要なので、自己参照および前方参照はstructバージョンを使用します。主に#includeディレクティブの順序に関する問題を減らすため、ヘッダーファイルでこれを好みます。

PS:これはdoesどちらの言語でも動作し(C++ 11標準へのポインターについてはLRIOの回答を参照)、十分なバイリンガルおよび純粋なC++ヘッダーファイルでも使用されており、すぐに消えることはほとんどありません)どちらの言語でも機能する非常にシンプルなアプローチです。

5
Mike Housky