2011-08-02 8 views
2

こんにちは開発者!私はSkienaのアルゴリズム設計マニュアルブックからアルゴリズムを学んでいます。私はC++のように、このコードを書き換えるときC++のようにコーディングするとCコードが機能しません

gcc -Wall -o "test" "test.c" (in directory: /home/akacoder/Desktop/Algorithm_Design_Manual/chapter2) test.c: In function ‘insert_list’: test.c:15: warning: assignment from incompatible pointer type Compilation finished successfully.

:しかしそれはコンパイル時に警告を私に与え

#include <stdio.h> 
#include <stdlib.h> 

typedef int item_type; 

typedef struct{ 
    item_type item; 
    struct list* next; 
    }list; 

void insert_list(list **l, item_type x){ 
    list *p; 
    p = malloc(sizeof(list)); 
    p->item = x; 
    p->next = *l; 
    *l = p; 
    } 

int main(){ 
    return 0; 
    } 

:そこ私は、次のコードを持っている

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
using namespace std; 

typedef int item_type; 

typedef struct{ 
    item_type item; 
    struct list* next; 
    }list; 

void insert_list(list **l, item_type x){ 
    list *p; 
    p = malloc(sizeof(list)); 
    p->item = x; 
    p->next = *l; 
    *l = p; 
    } 

int main(){ 
    return 0; 
    } 

それは次を与える:

g++ -Wall -o "chapter2" "chapter2.cpp" (in directory: /home/akacoder/Desktop/Algorithm_Design_Manual/chapter2) chapter2.cpp:15: error: conflicting declaration ‘typedef struct list list’ chapter2.cpp:14: error: ‘struct list’ has a previous declaration as ‘struct list’ chapter2.cpp: In function ‘void insert_list(list**, item_type)’: chapter2.cpp: In function ‘void insert_list(list**, item_type)’: chapter2.cpp:19: error: invalid conversion from ‘void*’ to ‘list*’

誰でも可それはなぜそうプレーン? C++でどのように書き直すことができますか?

答えて

8

あなたの問題は両方とも構造体定義にあります:struct list *nextは、宣言の過程にある構造体を参照していません。代わりにこれを試してみてください。また

typedef struct list { 
    item_type item; 
    struct list* next; 
} list; 

を、あなたは適切なポインタ型(list *)へmallocによって返さvoid *をキャストする必要があり、C++で、C++は、これらのことについて厳しいです。また、BTW、C++では、必要に応じてtypedefを完全に終了することができます。

異なるエラーメッセージの理由は、言語の違いです。

Cでは、コンパイラはstruct list *が構造体へのポインタであることを知っているので、実際には "構造体リスト"が何であるかを実際には知らないと不平を言う必要はありません。後で、この "struct list *"を "list *"型のポインタ( "匿名の構造体へのポインタ"の型)から割り当てようとすると、それは不一致について文句を言います。

C++では、 "struct"宣言は多かれ少なかれ "クラス"宣言に相当します(主な違いはメンバーのデフォルトの可視性です)。とりわけ、これはC++の構造体が多かれ少なかれ自動的に型定義されることを意味します。したがって、コンパイラは "struct list * next"を見ると、それを "list"というクラスの前方宣言として受け取ります。ステートメントを終了してtypedefを処理すると、既に(前方に)何か他のものとして宣言されている識別子に何かをtypedefしようとしているので、エラーがスローされます。以前のエラーのために、実際に "リスト"が何であるかを知ることができないため、さらにエラーが発生します。これに

typedef struct{ 
    item_type item; 
    struct list* next; 
    }list; 

struct list { 
    item_type item; 
    list* next; 
    }; 

説明:最初の例では、匿名の構造を持っている、struct listが前方に宣言されている内

+0

前の宣言を持つ必要はなく、前方宣言として 'struct list * next'を解釈します。 –

+0

@GeneBushuyev:良い点、私は文言を調整しました。 – Anomie

9

これは、型変換に関してC++がcよりも厳しいためです。

コードに他にも多数のエラーがあります。ファイルの名前を.cpp &としてg++を使ってコンパイルしても、CソースコードをC++にすることはできません。

あなたはc++でプログラムを書いている場合はそうあなたが明示的にmallocの場合のようにキャストを入力する必要はありませんやって、new &ないmallocを使用してください。

+0

そして、私はdownvoteの属性は何ですか? –

+1

この回答はより具体的にする必要があります。「あなたのコードには他の多くのエラーがあります。 –

+2

@クリス・ジョンソン:私が間違った部分を書き終えたら、他の回答はすでにエラーの「精緻化されたリスト」を思い付いてしまっていますが、ここで同じことを繰り返す価値はないと答えました。 &私が作りたいと思ったこと。 –

5

C++は任意のポインタ変換を許可しませんが、Cは行いません。しかし、これは良いスタイルとは考えられないので、コンパイラは警告を出します。

だけのキャストを追加し、それが両方のメッセージ解決します:

p = (list*)malloc(sizeof(list)); 

それとも、C++のみになりたい場合:

p = new list; 

しかし、その後、あなたはまた、コンストラクタとそのように宣言する必要があります。

+0

'malloc()'の結果をキャストすることは、Cの* poor *スタイルとみなされます。たとえば、 '#include 'を忘れた場合、一部のコンパイラは 'malloc()'がintを返すと仮定します。型の不一致を避けるイディオムは 'p = malloc(sizeof * p);'です。 –

+0

そして、CまたはC++としてコンパイルされるコードを書こうとしているなら、おそらく間違っているでしょう。 C/C++の相互運用性は十分であるため、これを行う理由はほとんどありません。 –

0

Cのみが警告を発するので、C++ではエラーが発生する可能性があります。

プログラミング文化的なものです。 Cはタイピングシステムを強制しないことで非常に寛容でした。 C++はまだまだ寛容ですが、C++でさえも許さないものをCでやっています。

メモリブロックをmallocするときは、そのメモリブロックをリストへのポインタにキャストします。これは、アドレス(ポインタ)を正しいタイプのポインタに変換します。

このキャストがなければ、mallocされたサイズのものがあり、それがリストポインタや他のポインタによって参照されることを意図しているかどうかは分かりません。

+0

Cでは、 'malloc()'の結果をキャストすることは、エラーを作成するか隠す可能性が高くなります。ポインタオブジェクトに結果を代入するだけです。 void *から任意のポインタ型への暗黙的な変換が残りを処理します。 'p = malloc(sizeof * p);'を使うと、すべてのサイズと型が一貫して正しいことを保証できます。 (これはCに特有です; C++では、とにかく 'malloc()'を使うべきではないでしょう。) –

3

あなたはこのクラスを変更する必要があります。したがって、typedefはC++の構造体宣言と同じではないため、コンパイラは次の行でtypedefを見ると名前の衝突を検出します。

+0

全くありません。 'list * next ';' 'list"は宣言されていません。 (C++では "struct list"を "list"と呼ぶことができますが、Cではそうではありません)あなたは 'struct list {item_type item;構造体リスト* next; }; '(そして、その型を" struct list "と呼ぶ)、または、typedef struct list {item_type item;構造体リスト* next; }リスト; '。 –

+0

@Keith - 'list * next;'が宣言されています(コンパイラは別の方法で失敗しました)。クラス本体の内部ではすべての名前(クラス名だけでなく)が可視です。おそらくあなたが言いたいのは、 'list'はその時点で不完全であるということです。これは、コンパイラが不完全な型のポインタを取ることを妨げません。 –

+0

C++では、 'struct list'の宣言は、不完全型であっても、その型を' list'と呼ぶことができます。 Cでは、そうではありません。そのため、Cコードでは一般に構造体型にtypedefを使用しています。 (私の好みは、typedefを省略し、その型を 'struct list'と呼ぶことです) –

4

これは、this linkで説明されています。

引用:何をやっているので、

Gotcha for a C++ programmer using C

Structs and Enums

You have to include the struct keyword before the name of the struct type to declare a struct: In C++, you could do this

struct a_struct { int x; };

a_struct struct_instance;

and have a new instance of a_struct called struct_instance . In C, however, we have to include the struct keyword when declaring struct_instance :

struct a_struct struct_instance;

In fact, a similar situation also holds for declaring enums: in C, you must include the keyword enum ; in C++, you don't have to. As a side note, most C programmers get around this issue by using typedefs:

typedef struct struct_name { /* variables */ } struct_name_t;

Now you can declare a struct with

struct_name_t struct_name_t_instance;

But there is another gotcha for C++ programmers: you must still use the " struct struct_name " syntax to declare a struct member that is a pointer to the struct .

typedef struct struct_name { 
    struct struct_name instance; 
    struct_name_t instance2; /* invalid! The typedef isn't defined 
yet */ } struct_name_t; 
2

が本当にstructを定義して、typedefでエイリアスを作成している私はそれがCの場合にはこれを実行する方が読みやすいと思う:

typedef struct list_ { 
    item_type item; 
    struct list_* next; 
} list; 
+0

タグ(list_)と型定義名(list)に異なる識別子を使用するのはなぜですか?構造体タグは異なる名前空間(Cの意味で)にあるので、 'typedef struct list {...} list;'; "struct list"と "list"は同じ型の2つの異なる名前です。 –

+0

@Keithあなたが正しいと思うのですが、このスタイルはユーザーが 'struct list_'を使わないでくださいが、主に一貫性のために' typedef'を通らなければならないという印象を与えるからです。 – mgalgs

1

次のコードを使用してください

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
using namespace std; 

typedef int item_type; 

struct list{ 
    item_type item; 
    list* next; 
}; 

void insert_list(list **l, item_type x){ 
    list *p; 
    p = (list*)malloc(sizeof(list)); 
    p->item = x; 
    p->next = *l; 
    *l = p; 
} 

int main(){ 
    return 0; 
} 
+0

なぜ 'malloc'ですか?これはC++ではないはずです! –

関連する問題