私は以下のような構造からなる多くのプログラムを見てきました
typedef struct
{
int i;
char k;
} elem;
elem user;
なぜそんなに頻繁に必要なのですか?特定の理由または該当する領域はありますか?
struct * ptr
があります。構造体の内部の行がエラーの原因となるため、匿名の構造体でリンクリストを作成できないと思います
私は以下のような構造からなる多くのプログラムを見てきました
typedef struct
{
int i;
char k;
} elem;
elem user;
なぜそんなに頻繁に必要なのですか?特定の理由または該当する領域はありますか?
struct * ptr
があります。構造体の内部の行がエラーの原因となるため、匿名の構造体でリンクリストを作成できないと思います
回答:
グレッグ・ヒューギルが言ったように、typedefは、あちこちに書く必要がないことを意味しますstruct
。これはキーストロークを節約するだけでなく、smidgenをより抽象化するため、コードをよりクリーンにすることもできます。
のようなもの
typedef struct {
int x, y;
} Point;
Point point_new(int x, int y)
{
Point a;
a.x = x;
a.y = y;
return a;
}
「struct」キーワードをあちこちに表示する必要がない場合は、よりきれいになり、言語に「Point」と呼ばれるタイプが実際にあるかのように見えます。これは、の後にtypedef
、私が推測するケースです。
また、あなたの例(と私)はstruct
それ自体の名前を省略しましたが、実際に名前を付けることは、不透明なタイプを提供したい場合にも役立ちます。次に、たとえば次のようなコードをヘッダーに含めます。
typedef struct Point Point;
Point * point_new(int x, int y);
次にstruct
、実装ファイルで定義を提供します。
struct Point
{
int x, y;
};
Point * point_new(int x, int y)
{
Point *p;
if((p = malloc(sizeof *p)) != NULL)
{
p->x = x;
p->y = y;
}
return p;
}
後者の場合、その定義はヘッダーファイルのユーザーから隠されるため、値でポイントを返すことはできません。これは、たとえばGTK +で広く使用されている手法です。
更新このtypedef
非表示の使用がstruct
悪い考えと見なされている非常に評判の高いCプロジェクトもあることに注意してください。Linuxカーネルはおそらく最もよく知られているそのようなプロジェクトです。Linusの怒った言葉については、Linux Kernel CodingStyleドキュメントの第5章を参照してください。:)私のポイントは、結局のところ、問題の「べき」はおそらく固いものではないということです。
多くの人がこれを間違えているのは驚くべきことです。Cではtypedef構造体を使用しないでください。大規模なCプログラムでは通常非常に汚染されているグローバル名前空間を不必要に汚染します。
また、タグ名のないtypedefされた構造体は、ヘッダーファイル間の順序関係の不必要な強制の主な原因です。
検討してください:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
typedefを使用せずにそのような定義を使用すると、compilandユニットがfoo.hをインクルードしてFOO_DEF
定義を取得することが可能です。foo
構造体の「bar」メンバーを逆参照しようとしない場合は、「bar.h」ファイルを含める必要はありません。
また、名前空間はタグ名とメンバー名で異なるため、次のような非常に読みやすいコードを書くことができます。
struct foo *foo;
printf("foo->bar = %p", foo->bar);
名前空間は分離されているため、構造体タグ名と一致する変数の命名に競合はありません。
コードを維持する必要がある場合は、typedefされた構造体を削除します。
typedef struct X { ... } X
です。そうすれX
ば、定義が使用可能な場所であればどこでも構造体をアドレス指定するために短い形式を使用できますがstruct X
、必要に応じて前方宣言して使用できます。
Dan Saksによる古い記事(http://www.ddj.com/cpp/184403396?pgno=3)から:
構造体の命名に関するC言語のルールは少し風変わりですが、無害です。ただし、C ++のクラスに拡張すると、これらの同じルールは、バグがクロールするための小さな亀裂を開きます。
Cでは、名前sは
struct s { ... };
タグです。タグ名はタイプ名ではありません。上記の定義を前提として、次のような宣言
s x; /* error in C */ s *p; /* error in C */
Cのエラーです。次のように記述する必要があります。
struct s x; /* OK */ struct s *p; /* OK */
共用体と列挙の名前も型ではなくタグです。
Cでは、タグは他のすべての名前(関数、型、変数、および列挙定数)とは異なります。Cコンパイラは、概念的には他のすべての名前を保持するテーブルから物理的に分離していないとしても、概念的にはシンボルテーブルにタグを保持します。したがって、Cプログラムは、同じスコープで同じスペルのタグと別の名前の両方を持つことができます。例えば、
struct s s;
タイプstruct sの変数sを宣言する有効な宣言です。良い方法ではないかもしれませんが、Cコンパイラはそれを受け入れる必要があります。Cがこのように設計された理由を説明したことはありません。いつも間違いだと思っていましたが、間違いです。
多くのプログラマー(本当にあなたを含む)は、構造体名をタイプ名と考えることを好むため、typedefを使用してタグのエイリアスを定義します。たとえば、定義
struct s { ... }; typedef struct s S;
次のように、構造体sの代わりにSを使用できます。
S x; S *p;
プログラムは、型と変数(または関数または列挙定数)の両方の名前としてSを使用できません。
S S; // error
これはいい。
構造体、共用体、または列挙型定義のタグ名はオプションです。多くのプログラマーは、次のように、構造体定義をtypedefに折りたたみ、タグを完全に省略します。
typedef struct { ... } S;
リンクされた記事には、Cが動作しないことを要求しないというC ++の動作が、typedef
名前の非表示の微妙な問題をどのように引き起こすかについての議論もあります。これらの問題を防ぐために、typedef
一見すると不要であるように見えても、C ++のクラスと構造体にも良い考えです。C ++では、typedef
名前を非表示にすると、潜在的な問題の隠された原因ではなく、コンパイラーが通知するエラーになります。
int stat(const char *restrict path, struct stat *restrict buf)
関数を使用する(POSIXまたはUnix)プログラムにあります。そこstat
では、通常の名前空間とstruct stat
タグ名前空間に関数があります。
typedef
回避策を使用するとstruct
、その型の変数を宣言するたびに書き込む必要がなくなります。
struct elem
{
int i;
char k;
};
elem user; // compile error!
struct elem user; // this is correct
typedef
一般的にING構造を否定する理由にはなりません。あなたも行うことができますtypedef struct foo foo;
。もちろん、struct
キーワードはそれ以上必要ありません。これは、私たちが見る型エイリアスが構造体のエイリアスであることを示唆する有用なヒントになりますが、一般的に悪くはありません。結果の型エイリアスの識別子が、typedef
それが構造体fe:のエイリアスであることを示す場合も考えてくださいtypedef struct foo foo_struct;
。
常にtypedef enumsとstructsを使用するもう1つの理由は、この問題の結果です。
enum EnumDef
{
FIRST_ITEM,
SECOND_ITEM
};
struct StructDef
{
enum EnuumDef MyEnum;
unsigned int MyVar;
} MyStruct;
構造体のEnumDefのタイプミスに注意してください(Enu u Enu mDef)のください。これはエラー(または警告)なしでコンパイルされ、(C標準の文字どおりの解釈に応じて)正しいです。問題は、構造体内に新しい(空の)列挙定義を作成したことです。以前の定義EnumDefは(意図したとおりに)使用していません。
typdefを使用すると、同様のタイプのタイプミスにより、不明なタイプを使用するとコンパイラエラーが発生します。
typedef
{
FIRST_ITEM,
SECOND_ITEM
} EnumDef;
typedef struct
{
EnuumDef MyEnum; /* compiler error (unknown type) */
unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */
構造体と列挙型を常にtypedefすることを推奨します。
タイピングを節約するためだけでなく(意図的なしゃれはありません;))、それがより安全だからです。
enum
多くのコンパイラは「間違った」使用をすると奇妙な警告を発するため、通常、型として使用することはお勧めしません。たとえば、enum
0 に初期化すると、「列挙型にない整数定数」の警告が表示される場合があります。を前方宣言するenum
こともできません。代わりにint
(またはunsigned int
)を使用する必要があります。
Linuxカーネルコーディングスタイルの第5章では、を使用する場合の長所と短所(主に短所)を示していtypedef
ます。
「vps_t」などは使用しないでください。
構造体とポインタにtypedefを使用するのは誤りです。あなたが見たとき
vps_t a;
ソースでは、それはどういう意味ですか?
対照的に、それが言うなら
struct virtual_container *a;
あなたは実際に「a」が何であるかを言うことができます。
多くの人々は、typedefは「読みやすさを助ける」と考えています。そうではありません。これらは、次の場合にのみ役立ちます。
(a)完全に不透明なオブジェクト(typedefはオブジェクトを非表示にするためにアクティブに使用されます)。
例: "pte_t"など。適切なアクセサ関数を使用しないとアクセスできない不透明なオブジェクト。
注意!不透明度と「アクセサ機能」はそれ自体では良くありません。pte_tなどのようなもののためにそれらを持っている理由は、そこに移植可能なアクセス可能な情報が絶対にゼロであるためです。
(b)明確な整数型。抽象化は、それが「int」であるか「long」であるかの混乱を回避するのに役立ちます。
u8 / u16 / u32は完全にすばらしいtypedefですが、ここよりもカテゴリ(d)に適しています。
注意!繰り返しますが、これには理由が必要です。「署名されていない長い」ものがある場合、行う理由はありません
typedef unsigned long myflags_t;
しかし、特定の状況下で「unsigned int」であり、他の構成では「unsigned long」になる理由が明確な場合は、必ず先に進んでtypedefを使用してください。
(c)スパースを使用して文字通り型チェック用の新しい型を作成する場合。
(d)特定の例外的な状況において、標準のC99タイプと同一の新しいタイプ。
目と脳が 'uint32_t'のような標準型に慣れるのにほんの少しの時間しかかかりませんが、一部の人々はとにかくその使用に反対します。
したがって、Linux固有の「u8 / u16 / u32 / u64」タイプと、標準タイプと同じである署名付きの同等物が許可されます。ただし、独自の新しいコードでは必須ではありません。
タイプのセットのいずれかをすでに使用している既存のコードを編集するときは、そのコードの既存の選択に準拠する必要があります。
(e)ユーザースペースで使用しても安全なタイプ。
ユーザー空間に表示される特定の構造では、C99タイプを要求できず、上記の 'u32'形式を使用できません。したがって、ユーザースペースと共有されるすべての構造で__u32および類似のタイプを使用します。
他のケースもあるかもしれませんが、これらのルールの1つに明確に一致することができない限り、基本的にtypedefを決して使用しないようにする必要があります。
一般に、ポインタ、または合理的に直接アクセスできる要素を持つ構造体は、typedefにしないでください。
長所と短所があることがわかります。有用な情報源は、精力的な本「エキスパートCプログラミング」(第3章)です。簡単に言うと、Cには複数の名前空間があります。タグ、タイプ、メンバー名、識別子です。typedef
型のエイリアスを導入し、それをタグ名前空間に配置します。つまり、
typedef struct Tag{
...members...
}Type;
2つのことを定義します。タグ名前空間の1つのタグとタイプ名前空間の1つのタイプ。したがって、Type myType
との両方を実行できますstruct Tag myTagType
。struct Type myType
またはのような宣言Tag myTagType
は違法です。さらに、次のような宣言では:
typedef Type *Type_ptr;
Typeへのポインタを定義します。したがって、次のように宣言したとします。
Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;
次にvar1
、var2
およびmyTagType1
TypeへのポインタmyTagType2
ですが、そうではありません。
上記の本の中で、typedefing構造体はプログラマが単語structを書く手間を省くだけなのであまり有用ではないと述べています。ただし、他の多くのCプログラマーと同様に、私は反対意見を持っています。Cでポリモーフィズムを実装する場合、一部の名前が難読化されることがあります(そのため、カーネルなどの大規模なコードベースではお勧めできません)。詳細については、こちらを参照してください。例:
typedef struct MyWriter_t{
MyPipe super;
MyQueue relative;
uint32_t flags;
...
}MyWriter;
できるよ:
void my_writer_func(MyPipe *s)
{
MyWriter *self = (MyWriter *) s;
uint32_t myFlags = self->flags;
...
}
したがって、外部メンバー(flags
MyPipe
、キャストを通じて内部構造体()によって)に。私にとっては、その(struct MyWriter_ *) s;
ような機能を実行するたびに行うよりも、型全体をキャストする方が混乱が少ないです。このような場合、コード内でこの手法を多用する場合は特に、簡単な参照が重要になります。
最後に、typedef
ed型の最後の側面は、マクロとは対照的に、それらを拡張できないことです。たとえば、次の場合:
#define X char[10] or
typedef char Y[10]
次に宣言できます
unsigned X x; but not
unsigned Y y;
構造体の場合、ストレージ指定子(volatile
およびconst
)には適用されないため、これについては特に気にしません。
MyPipe *s; MyWriter *self = (MyWriter *) s;
そして、あなたは厳密なエイリアシングを壊しました。
typedef struct Tag{ ...members... }Type;
2つのことを定義する」はまったく意味がありません。typedefがタグを定義する場合、ここでの「タイプ」もタグでなければなりません。真実は(。確かまたは2種類と1個のタグではない)の定義は2個のタグや1型を定義している:struct Tag
、Tag
とType
。struct Tag
間違いなくタイプです。Tag
タグです。しかし、混乱はType
タグなのかタイプなのか
typedefを使用して前方宣言を行うこともできません。構造体、列挙型、および共用体を使用すると、依存関係(について知っている)が双方向である場合に宣言を転送できます。
スタイル:C ++でのtypedefの使用はかなり理にかなっています。これは、複数のパラメータや変数パラメータを必要とするテンプレートを扱う場合にほとんど必要になる可能性があります。typedefは命名をまっすぐに保つのに役立ちます。
Cプログラミング言語ではそうではありません。typedefの使用は、ほとんどの場合、データ構造の使用を難読化する以外に目的はありません。{struct(6)、enum(4)、union(5)}の数のキーストロークのみがデータ型の宣言に使用されるため、structのエイリアシングはほとんど使用されません。そのデータ型は共用体または構造体ですか?型定義されていない単純な宣言を使用すると、その型がすぐにわかります。
Linuxがこのエイリアシングを厳密に回避してどのように書かれているかに注意してください。結果は、ミニマリストでクリーンなスタイルです。
struct
どこでも繰り返されないでしょう... Typedefは新しいタイプを作ります。あなたは何を使うのですか?タイプ。私たちはしていない気にそれは構造体、共用体、または列挙型かどうなぜそれtypedefのことです。
FILE
どれがaのようなものであるかを気にする必要がありますか?
基本から始めましょう。
構造定義の例を次に示します。
struct point
{
int x, y;
};
ここでは、名前point
はオプションです。
構造体は、その定義中または後に宣言できます。
定義中の宣言
struct point
{
int x, y;
} first_point, second_point;
定義後の宣言
struct point
{
int x, y;
};
struct point first_point, second_point;
ここで、上記の最後のケースに注意してください。struct point
コードの後半でその型を作成する場合は、その型の構造体を宣言するように記述する必要があります。
と入力しtypedef
ます。プログラムで同じブループリントを使用して後で新しい構造(構造はカスタムデータ型)を作成する場合は、typedef
その定義中に使用することをお勧めします。
typedef struct point
{
int x, y;
} Points;
Points first_point, second_point;
カスタムタイプ名の末尾に_tサフィックスを使用することを妨げるものは何もありませんが、POSIX標準では、標準ライブラリタイプ名を示すためにサフィックス_tの使用を予約しています。
構造体に(オプションで)指定する名前はタグ名と呼ばれ、前述のとおり、それ自体は型ではありません。タイプに到達するには、構造体の接頭辞が必要です。
GTK +は別として、タグ名がstruct型のtypedefと同じくらい一般的に使用されているかどうかはわかりません。そのため、C ++では認識され、structキーワードを省略して、タグ名を型名として使用することもできます。
struct MyStruct
{
int i;
};
// The following is legal in C++:
MyStruct obj;
obj.i = 7;
A> typdefは、データ型のより意味のある同義語の作成を許可することにより、プログラムの意味とドキュメント化を支援します。さらに、移植性の問題(K&R、pg147、C prog lang)に対するプログラムのパラメーター化を支援します。
B> 構造体はタイプを定義します。Structsを使用すると、varのコレクションをグループ化して、単一のユニットとして扱いやすくすることができます(K&R、pg127、Cプログラム言語)。
C>構造体のtypedefについては、上記のAで説明しています。
D>私にとって、構造体はカスタムタイプ、コンテナ、コレクション、名前空間、または複雑なタイプですが、typdefは、より多くのニックネームを作成するための手段にすぎません。
C99ではtypedefが必要であることが判明しました。時代遅れですが、多くのツール(HackRankとして)は、純粋なC実装としてc99を使用しています。そして、typedefが必要です。
要件が変更された場合、それらを変更する必要があるとは言っていません(おそらく2つのCオプションがあります)。
typedef
が必要です。」どういう意味ですか?
C
ではなく、についてC++
です。C
typedefである「必要な」(最も可能性の高い常になります)。'必須'の場合と同様に、変数を宣言しPoint varName;
て型をstruct Point;
なしで同義にすることはできませんtypedef struct Point Point;
。
'C'プログラミング言語では、キーワード 'typedef'を使用して、オブジェクト(構造体、配列、関数..enum型)の新しい名前を宣言します。たとえば、「struct-s」を使用します。「C」では、「メイン」関数の外で「構造体」を宣言することがよくあります。例えば:
struct complex{ int real_part, img_part }COMPLEX;
main(){
struct KOMPLEKS number; // number type is now a struct type
number.real_part = 3;
number.img_part = -1;
printf("Number: %d.%d i \n",number.real_part, number.img_part);
}
構造体型を使用することを決定するたびに、このキーワード 'struct' something '' name 'が必要になります。'typedef'はその型の名前を変更するだけで、プログラムでその名前をいつでも使用できます。したがって、コードは次のようになります。
typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.
main(){
COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);
}
プログラム全体で使用されるローカルオブジェクト(構造体、配列、貴重なもの)がある場合は、 'typedef'を使用して名前を付けるだけです。
まったく、C言語では、struct / union / enumはC言語のプリプロセッサによって処理されるマクロ命令です( "#include"などを扱うプリプロセッサと間違えないでください)。
そう :
struct a
{
int i;
};
struct b
{
struct a;
int i;
int j;
};
struct bは次のように使用されます。
struct b
{
struct a
{
int i;
};
int i;
int j;
}
したがって、コンパイル時にスタック上で次のように展開されます:b:int ai int i int j
そのため、自己参照構造体を持つのが難しいのです。Cプリプロセッサは、終了できない宣言ループで丸めます。
typedefは型指定子です。つまり、Cコンパイラのみがそれを処理し、アセンブラコードの実装を最適化するために必要な処理を実行できます。また、préprocessorが構造体で行うようにpar型のメンバーを愚かに消費しませんが、より複雑な参照構築アルゴリズムを使用するため、次のような構築を行います。
typedef struct a A; //anticipated declaration for member declaration
typedef struct a //Implemented declaration
{
A* b; // member declaration
}A;
許可され、完全に機能します。この実装は、コンパイラー型変換へのアクセスも提供し、実行スレッドが初期化関数のアプリケーションフィールドを離れたときのいくつかのバグの影響を取り除きます。
つまり、Cでは、typedefは孤独な構造体よりもC ++クラスに近いということです。
structs
typedef
typedef
struct
struct b
struct a *
typedef
struct
typedef