1. 構造体はメモリにどのように保存されますか?int メイン() { 学生スタ; スタッ.id = 123456; strcpy(stu.name,"feizhufeifei"); stu.math = 90; ステュー.PE = 80; printf("生徒:%p\r\n",&stu); printf("stu.ID:%p\r\n",&stu.ID); printf("stu.name:%p\r\n",&stu.name); printf("stu.math:%p\r\n",&stu.math); 0を返します。 } 印刷結果は次のとおりです。 //構造体のアドレス Student:0xffffcbb0 //構造体の最初のメンバーのアドレス stu.ID:0xffffcbb0 //オフセットアドレス + 0 stu.name:0xffffcbb4//オフセットアドレス + 4 stu.math:0xffffcbd4 //オフセットアドレス + 24 構造体のアドレスは構造体の最初のメンバーのアドレスと同じであることがわかります。これが、「車輪の再発明を拒否! Linux カーネルの一般的なリンク リストを移植して使用する方法 (完全なコード実装付き)」で、構造体の最初に struct list_head を配置する必要がある理由について説明した理由です。 よくわからない場合は、次の 2 つの例を見てください。
構造体のメンバー変数は実際にはメモリ内のオフセット アドレスとして格納されていることがわかります。つまり、構造体 A のアドレス + メンバー変数のオフセット アドレス = 構造体メンバー変数の開始アドレスです。 したがって、構造体変数の開始アドレスとメンバー変数のオフセット アドレスに基づいて、構造体 A のアドレスを推測することもできます。 2. container_ofマクロ#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member)*__mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); }) まず、3 つのパラメータを見てみましょう。ptr はメンバー変数へのポインタ、type は構造体の型、member はメンバー変数の名前です。 container_of マクロの機能は、構造体内のメンバー変数のアドレス、変数名、および構造体の型を通じて構造体変数のアドレスを見つけることです。ここで使用されるトリックは、コンパイラ テクノロジを使用することです。これは、まず構造体内の構造体メンバーのオフセットを見つけ、次にメンバー変数のアドレスに基づいてメイン構造体変数のアドレスを見つけるというものです。以下、各部分の詳細な分析です。 3. 型まず、変数の型を返すために使用される typeof を見てみましょう。これは GCC コンパイラの拡張機能であり、typeof はコンパイラに依存します。これは C 言語仕様では必須ではなく、標準の一部でもありません。 int メイン() { 整数a = 5; //ここでaと同じ型の変数bを定義します 型aはb = 6です。 printf("%d,%d\r\n",a,b);//5 6 0を返します。 } 4. (((タイプ *)0)->メンバー)((TYPE *)0) は、0 を type 型の構造体ポインタに変換します。言い換えると、コンパイラは構造体がプログラム セグメントの先頭 0 から始まると考えます。アドレス 0 から始まる場合、取得するメンバー変数のアドレスは、メンバー変数のオフセット アドレスと直接等しくなります。 (((type *)0)->member) は、構造体内の MEMBER メンバーを参照します。 typedef 構造体学生{ 整数ID; 文字名[30]; 整数数学; }学生; int メイン() { //ここでは、構造体が強制的にアドレス 0 に変換され、その後、name のアドレスが出力されます。 printf("%d\r\n",&((生徒 *)0)->名前);//4 0を返します。 } 5. const typeof(((type * )0) ->member)*__mptr = (ptr);このコードは、 なぜこれを行う代わりに 6. offsetof(型、メンバー)
size_t は標準 C ライブラリで定義されており、通常 32 ビット アーキテクチャでは次のように定義されます。
64 ビット アーキテクチャでは次のように定義されます。
定義からわかるように、size_t は負でない数なので、通常はカウントに size_t が使用されます (カウントには負の領域は必要ないため)。
プログラムの移植性を高めるために、カーネルは int と unsigned の代わりに 7. (type * )((char * )__mptr - offsetof(type, member))この文は、 8. 例#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) typedef 構造体 学生 { 整数ID; 文字名[30]; 整数数学; }学生; int メイン() { 学生スタ; 学生 *sptr = NULL; スタッ.id = 123456; strcpy(stu.name,"zhongyi"); stu.math = 90; sptr = container_of(&stu.id,学生、id); printf("sptr=%p\n",sptr); sptr = container_of(&stu.name,生徒,名前); printf("sptr=%p\n",sptr); sptr = container_of(&stu.math,学生,id); printf("sptr=%p\n",sptr); 0を返します。 } 結果は次のとおりです。
マクロ展開でより明確になるかもしれない int メイン() { 学生スタ; 学生 *sptr = NULL; スタッ.id = 123456; strcpy(stu.name,"zhongyi"); stu.math = 90; //展開して置換 sptr = ({ const unsigned char *__mptr = (&stu.id); (Student *)( (char *)__mptr - ((size_t) &((Student *)0)->id) );}); printf("sptr=%p\n",sptr); //展開して置換 sptr = ({ const unsigned char *__mptr = (&stu.name); (Student *)( (char *)__mptr - ((size_t) &((Student *)0)->name) );}); printf("sptr=%p\n",sptr); //展開して置換 sptr = ({ const unsigned int *__mptr = (&stu.math); (Student *)( (char *)__mptr - ((size_t) &((Student *)0)->math) );}); printf("sptr=%p\n",sptr); 0を返します。 } LinuxカーネルのContainer_Ofマクロの詳細説明はこれで終了です。LinuxカーネルのContainer_Ofマクロの詳細については、123WORDPRESS.COMの過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも123WORDPRESS.COMをよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: 実用的な MySQL + PostgreSQL バッチ挿入更新 insertOrUpdate
>>: JSコンストラクタとインスタンス化およびプロトタイプ導入の関係
ページを作成するときに、記述した CSS スタイルが有効にならないことがあります。この現象にはさまざ...
Tomcat を学習したばかりのプログラマーにとって、これはよくある間違いです。 1. 環境変数の問...
個々のウェブマスターにとって、自分のウェブサイトをいかにユニークで個性あふれるものにするかは、常に絶...
1. DockerはローカルディレクトリをマウントしますDocker は、ホスト上のディレクトリをイ...
目次JSONPとはJSONP 原則JSONP実装1. Ajaxでクロスドメインリクエストが行われると...
コンテナはすでに作成されていますが、その起動パラメータ(データがマウントされる場所)を知る方法 #コ...
他の人のウェブページを保存して見たことがあると思いますが、特にdwで開くと、多くのウェブページに&l...
VueはPCカメラを呼び出してリアルタイムで写真を撮影します。参考までに、具体的な内容は次のとおりで...
折りたたみ表示の複数行テキストコンポーネント複数行のテキスト コンポーネントを折りたたんで表示し、展...
目次HTMLの実装CSSを追加Javascript部分の実装デモアドレス HTMLの実装まず、hea...
1. ElasticSearch 6.4.1 インストール パッケージを次の場所からダウンロードしま...
まずはレンダリングを見てみましょう: XML/HTML コードコンテンツをクリップボードにコピー&l...
目次導入インデックスの原則1. データページ2. ページディレクトリ3. インデックス原則分析要約す...
オンラインで多くの記事を検索しましたが、解決策は見つかりませんでした。次のように、tomcat7-m...
目次落とし穴充填方法何の穴ですか?要約する落とし穴最近、仕事で商品の割引価格を計算すると、いつも1セ...