まず、初期化ルールのセクション
なぜ初期化を説明する前に、最初に後で使用するために、C言語の初期化ルールを述べました。
私たちは、このように初期化される配列で使用することができます:
チャー BUF [ 10 ] = { 0 }。
次いで チャー BUF [ 10 ] = { 1 }、各アレイの各要素は、1つのアウトに初期化されていませんか?
初期化要素を指定するときに実際には、コンパイラの特性に応じて、配列要素の総数よりも少ない素子数場合、他の要素がゼロに初期化されます。
私たちは、コードの一部を確認するために、この機能を使用することができます。
1つの#include <stdio.hの> 2 3 INT メイン() 4 { 5 チャー BUF [ 10 ] = { 1 }。 6 7 戻り 0 。 8 }
分解は、次のように:
1 <メイン>: 2 プッシュ {FP} 。(STRのFP、[SP、#-4]!) 3 加算 FP、SP、#0 4 サブ SP、SP、#20 5 サブ R3、FP、#16 6 のMOV R2、#0 7つの STR R2、[R3] 8つの STR R2、[R3、#4 ] 9つの STRH R2、[R3、#8 ] 10の MOV R3、#は1 11 のSTRB R3、[FP、# - 16 ] 12 のMOV R3、#0 13 MOVR0、R3 14 加算 SP、FP#0 15 ポップ {FP} 。(LDRのFP、[SP]、#4) 16 のBX LR
コンパイルされたコードの部分列6-11前記アレイ1に割り当てられたプログラムの最初のバイト、残りのバイトはゼロに割り当てられていることを除いて、明確。
第二に、グローバル変数の初期化セクション
我々は、初期化されるグローバル変数を作成する方法については、以下のあなたが0の変数の初期値を作成する場合は、その後、「= 0」の割り当てはそれを省略することができます言いましたか?
料金はすべてを説明するためのコードを使用して、あまり話をしませんでした。
次のシナリオは、プロジェクトの実現のために、同社は、module_a.cプログラマはプログラムを書く場合は、彼の同僚は次のように最後の二人は、ソースコードを書くために、module_b.cのBプログラムを書きました:
1 / * module_a.c * / 2の#include <stdio.hの> 3 4 ボイド関数(ボイド)。 5 6 INT グローバル = 0 。 7 8 のint main()の 9 { 10 グローバル = 3 。 11 関数(); 12 のprintf(" メイン:%Dを\ n "、グローバル)。 13 リターン 0 。 14 }
1 / * module_b.c * / 2の#include <stdio.hの> 3 4 INT グローバル。 5 6 ボイド関数(ボイド) 7 { 8 グローバル = 6 。 9 のprintf(" 機能:%Dを\ n "、グローバル)。 10 リターン 0 ; 11 }
二人はグローバルと同じグローバル変数の協和定義を持っていますが、見落としBは、初期化しグローバルに忘れてしまいました。
通常でコンパイルされ、結果は以下の通りであります:
機能:6
メイン:6
私たちは、私の同僚、不可解な業績を生み出したモジュールのコンパイルを見ることができます。なぜ、同じ名前のグローバル変数を定義し、コンパイラがそれを訴えないのですか? 私たちは、探求し続けます。
まず、ソースファイルがオブジェクトファイルにコンパイルされ、その後、readelfがの内容を表示するためにツールを使用します。
腕のlinux-gccの- C module_x.c
腕 -linux-readelfが-a module_x.o
唯一のこれの関連する内容の除去 、次のようにグローバル識別子モジュールは、次のとおりです。
... [ 4 ] .bssのNOBITS 00000000 000078 000004 00 WA 0 0 4 ... 13:00000000 4 OBJECTグローバルなデフォルト 4 グローバル ...
次のようにBグローバル識別モジュールです。
... 12:00000004 4 OBJECTグローバルなデフォルトCOM グローバル ...
それは、グローバル変数が0に初期化されるセクションを.bssにするために組み合わさ、COM(共通ブロック)セグメントに組み込まれ、初期化されていないグローバル変数。その理由は、GCCコンパイラや従来のUNIX Cコンパイラ、共通ブロックに配置された初期化されていないグローバル変数のデフォルトの動作と一致して、 共通ブロックは弱いシンボル(weakシンボル)に相当し、そのリンクは文句を言わないとき、これはバグを特定するのは非常に難しいかもしれません。
Web上で見つかった以下の要約:
同じ名前とシンボリックリンクの弱いグローバルシンボルは間違って行くことができない、リンカはグローバルシンボルを選択します。グローバルシンボルおよび共通ブロック内の同じ名前の数である場合、同様に、リンカーは、グローバル・シンボルを選択します。つまり、リンクが初期化されていないグローバル変数が弱いシンボルであると考えられています。
もちろん、この出来事を回避する方法があり、私たちは、同じ名前のグローバル変数が存在する場合、コンパイル時にこの機能のgccをオフに-fno-共通の属性を追加することができ、それはエラーのリンク、ユーザーの意識を生成します。問題。