実行可能ファイルのどのセグメント(.BSS、.DATA、その他)に静的変数が格納されているため、名前の衝突が発生しませんか?例えば:
foo.c: bar.c:
static int foo = 1; static int foo = 10;
void fooTest() { void barTest() {
static int bar = 2; static int bar = 20;
foo++; foo++;
bar++; bar++;
printf("%d,%d", foo, bar); printf("%d, %d", foo, bar);
} }
両方のファイルをコンパイルして、それをfooTest()とbarTestを繰り返し呼び出すメインにリンクすると、printfステートメントは独立してインクリメントします。foo変数とbar変数は変換ユニットに対してローカルであるため、意味があります。
しかし、ストレージはどこに割り当てられていますか?
明確にするために、ELF形式でファイルを出力するツールチェーンがあることを前提としています。したがって、私は信じてそこにいることを持っているいくつかのスペースは、これらの静的変数の実行可能ファイルで予約します。
議論の目的で、GCCツールチェーンを使用すると仮定しましょう。
静力学がどこに行くかは、それらがゼロで初期化されているかどうかによって異なります。ゼロ初期化された静的なデータになります(ブロックは、シンボルによって開始).bssセクション、非ゼロ初期化されたデータは、に行く.DATA
プログラムがメモリにロードされると、さまざまなセグメントに編成されます。セグメントの1つはDATAセグメントです。データセグメントはさらに2つの部分に分割されます。
初期化されたデータセグメント:すべてのグローバル、静的、および定数データがここに格納されます。
初期化されていないデータセグメント(BSS):初期化されていないすべてのデータがこのセグメントに格納されます。
この概念を説明する図を次に示します。
これらの概念を説明する非常に良いリンクがあります:
http://www.inf.udec.cl/~leo/teoX.pdf
実際、変数はタプル(ストレージ、スコープ、タイプ、アドレス、値)です。
storage : where is it stored, for example data, stack, heap...
scope : who can see us, for example global, local...
type : what is our type, for example int, int*...
address : where are we located
value : what is our value
ローカルスコープは、定義された場所に応じて、トランスレーショナルユニット(ソースファイル)、関数、またはブロックのいずれかに対してローカルを意味します。変数を複数の関数から見えるようにするには、必ずDATAまたはBSS領域にある必要があります(それぞれ明示的に初期化されているかどうかによって異なります)。次に、ソースファイル内のすべての関数または関数のいずれかに応じてスコープが設定されます。
データの保存場所は実装によって異なります。
ただし、静的の意味は「内部リンケージ」です。したがって、シンボルはコンパイルユニット(foo.c、bar.c)の内部にあり、そのコンパイルユニットの外部で参照することはできません。したがって、名前の衝突はあり得ません。
自分でそれを見つける方法 objdump -Sr
何が起こっているのかを実際に理解するには、リンカーの再配置を理解する必要があります。それに触れたことがない場合は、最初にこの投稿を読むことを検討してください。
Linux x86-64 ELFの例を分析して、自分たちで確認してみましょう。
#include <stdio.h>
int f() {
static int i = 1;
i++;
return i;
}
int main() {
printf("%d\n", f());
printf("%d\n", f());
return 0;
}
コンパイル:
gcc -ggdb -c main.c
次のコードを逆コンパイルします。
objdump -Sr main.o
-S
元のソースが混在した状態でコードを逆コンパイルします-r
移転情報を表示しますの逆コンパイルの内部には、f
次のものがあります。
static int i = 1;
i++;
4: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # a <f+0xa>
6: R_X86_64_PC32 .data-0x4
そして、.data-0x4
それは.data
セグメントの最初のバイトに行くと言っています。
-0x4
私たちは、このように、アドレス指定のRIPの相対を使用しているので、そこで%rip
の指示にとR_X86_64_PC32
。
RIPは次の命令を指しているため、これが必要です。この命令は4バイトで始まり、その後00 00 00 00
に再配置されます。私はこれをより詳細に説明しました:https://stackoverflow.com/a/30515926/895245
次に、ソースをに変更i = 1
して同じ分析を行うと、次のように結論付けられます。
static int i = 0
に行く .bss
static int i = 1
に行く .data
「グローバルおよび静的」領域で:)
C ++にはいくつかのメモリ領域があります。
あなたの質問に対する詳細な答えについては、ここを参照してください:
以下は、C ++プログラムの主要な個別のメモリ領域をまとめたものです。一部の名前(「ヒープ」など)は、ドラフト[標準]にそのように表示されないことに注意してください。
Memory Area Characteristics and Object Lifetimes
-------------- ------------------------------------------------
Const Data The const data area stores string literals and
other data whose values are known at compile
time. No objects of class type can exist in
this area. All data in this area is available
during the entire lifetime of the program.
Further, all of this data is read-only, and the
results of trying to modify it are undefined.
This is in part because even the underlying
storage format is subject to arbitrary
optimization by the implementation. For
example, a particular compiler may store string
literals in overlapping objects if it wants to.
Stack The stack stores automatic variables. Typically
allocation is much faster than for dynamic
storage (heap or free store) because a memory
allocation involves only pointer increment
rather than more complex management. Objects
are constructed immediately after memory is
allocated and destroyed immediately before
memory is deallocated, so there is no
opportunity for programmers to directly
manipulate allocated but uninitialized stack
space (barring willful tampering using explicit
dtors and placement new).
Free Store The free store is one of the two dynamic memory
areas, allocated/freed by new/delete. Object
lifetime can be less than the time the storage
is allocated; that is, free store objects can
have memory allocated without being immediately
initialized, and can be destroyed without the
memory being immediately deallocated. During
the period when the storage is allocated but
outside the object's lifetime, the storage may
be accessed and manipulated through a void* but
none of the proto-object's nonstatic members or
member functions may be accessed, have their
addresses taken, or be otherwise manipulated.
Heap The heap is the other dynamic memory area,
allocated/freed by malloc/free and their
variants. Note that while the default global
new and delete might be implemented in terms of
malloc and free by a particular compiler, the
heap is not the same as free store and memory
allocated in one area cannot be safely
deallocated in the other. Memory allocated from
the heap can be used for objects of class type
by placement-new construction and explicit
destruction. If so used, the notes about free
store object lifetime apply similarly here.
Global/Static Global or static variables and objects have
their storage allocated at program startup, but
may not be initialized until after the program
has begun executing. For instance, a static
variable in a function is initialized only the
first time program execution passes through its
definition. The order of initialization of
global variables across translation units is not
defined, and special care is needed to manage
dependencies between global objects (including
class statics). As always, uninitialized proto-
objects' storage may be accessed and manipulated
through a void* but no nonstatic members or
member functions may be used or referenced
outside the object's actual lifetime.
衝突はないと思います。ファイルレベル(関数外)でstaticを使用すると、変数が現在のコンパイル単位(ファイル)に対してローカルとしてマークされます。現在のファイルの外部に表示されることはないため、外部で使用できる名前を付ける必要はありません。
関数内で静的を使用することは異なります-変数は関数にのみ表示され(静的かどうかに関係なく)、その値はその関数の呼び出し間で保持されます。
実際、staticは、それがどこにあるかに応じて2つの異なることを行います。では、両方しかし例、変数の可視性は、リンク時に使用すると、簡単に名前空間の衝突を防ぐことができますように制限されています。
そうは言ってDATA
も、ゼロ以外の値に初期化される変数を持つ傾向があるセクションに格納されると思います。もちろん、これは実装の詳細であり、標準で義務付けられているものではありません。これは、動作のみを考慮し、内部でどのように行われるかは考慮しません。
これが(理解しやすい)方法です:
使用しているプラットフォームとコンパイラによって異なります。一部のコンパイラは、コードセグメントに直接格納します。静的変数は常に現在の変換ユニットにのみアクセス可能であり、名前はエクスポートされないため、名前の衝突が発生することはありません。
コンパイル単位で宣言されたデータは、そのファイルの.BSSまたは.Data出力に送られます。BSSで初期化されたデータ、DATAで初期化されていないデータ。
静的データとグローバルデータの違いは、ファイルにシンボル情報が含まれていることです。コンパイラはシンボル情報を含める傾向がありますが、グローバル情報をそのようにマークするだけです。
リンカはこの情報を尊重します。静的変数のシンボル情報は破棄またはマングルされるため、静的変数は引き続き何らかの方法で参照できます(デバッグまたはシンボルオプションを使用)。どちらの場合も、リンカーが最初にローカル参照を解決するため、コンパイル単位が影響を受けることはありません。
objdumpとgdbで試してみましたが、次のような結果が得られました。
(gdb) disas fooTest
Dump of assembler code for function fooTest:
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: mov 0x200b09(%rip),%eax # 0x601040 <foo>
0x0000000000400537 <+10>: add $0x1,%eax 0x000000000040053a <+13>: mov %eax,0x200b00(%rip) # 0x601040 <foo> 0x0000000000400540 <+19>: mov 0x200afe(%rip),%eax # 0x601044 <bar.2180> 0x0000000000400546 <+25>: add $0x1,%eax
0x0000000000400549 <+28>: mov %eax,0x200af5(%rip) # 0x601044 <bar.2180>
0x000000000040054f <+34>: mov 0x200aef(%rip),%edx # 0x601044 <bar.2180>
0x0000000000400555 <+40>: mov 0x200ae5(%rip),%eax # 0x601040 <foo>
0x000000000040055b <+46>: mov %eax,%esi
0x000000000040055d <+48>: mov $0x400654,%edi 0x0000000000400562 <+53>: mov $0x0,%eax
0x0000000000400567 <+58>: callq 0x400410 <[email protected]>
0x000000000040056c <+63>: pop %rbp
0x000000000040056d <+64>: retq
End of assembler dump.
(gdb) disas barTest
Dump of assembler code for function barTest:
0x000000000040056e <+0>: push %rbp
0x000000000040056f <+1>: mov %rsp,%rbp
0x0000000000400572 <+4>: mov 0x200ad0(%rip),%eax # 0x601048 <foo>
0x0000000000400578 <+10>: add $0x1,%eax 0x000000000040057b <+13>: mov %eax,0x200ac7(%rip) # 0x601048 <foo> 0x0000000000400581 <+19>: mov 0x200ac5(%rip),%eax # 0x60104c <bar.2180> 0x0000000000400587 <+25>: add $0x1,%eax
0x000000000040058a <+28>: mov %eax,0x200abc(%rip) # 0x60104c <bar.2180>
0x0000000000400590 <+34>: mov 0x200ab6(%rip),%edx # 0x60104c <bar.2180>
0x0000000000400596 <+40>: mov 0x200aac(%rip),%eax # 0x601048 <foo>
0x000000000040059c <+46>: mov %eax,%esi
0x000000000040059e <+48>: mov $0x40065c,%edi 0x00000000004005a3 <+53>: mov $0x0,%eax
0x00000000004005a8 <+58>: callq 0x400410 <[email protected]>
0x00000000004005ad <+63>: pop %rbp
0x00000000004005ae <+64>: retq
End of assembler dump.
これがobjdumpの結果です
Disassembly of section .data:
0000000000601030 <__data_start>:
...
0000000000601038 <__dso_handle>:
...
0000000000601040 <foo>:
601040: 01 00 add %eax,(%rax)
...
0000000000601044 <bar.2180>:
601044: 02 00 add (%rax),%al
...
0000000000601048 <foo>:
601048: 0a 00 or (%rax),%al
...
000000000060104c <bar.2180>:
60104c: 14 00 adc $0x0,%al
つまり、4つの変数は、同じ名前でオフセットが異なるデータセクションイベントにあります。
前述のように、データセグメントまたはコードセグメントに格納されている静的変数。
スタックまたはヒープに割り当てられないことを確認できます。キーワードは変数のスコープをファイルまたは関数として定義するため、
衝突のリスクはありません。static
衝突の場合は、警告するコンパイラ/リンカーがあります。
良い例
この質問は少し古すぎますが、有用な情報を誰も指摘していないため、シンボルテーブルに同じ名前の静的変数が格納されていることを説明する「mohit12379」による投稿を確認してください。 http://www.geekinterview.com/question_details/24745
答えはコンパイラに非常に依存している可能性があるため、質問を編集することをお勧めします(つまり、セグメントの概念でさえ、ISOCまたはISOC ++では必須ではありません)。たとえば、Windowsでは、実行可能ファイルはシンボル名を持っていません。一方の「foo」はオフセット0x100で、もう一方はおそらく0x2B0であり、両方の変換ユニットからのコードは、「それらの」fooのオフセットを認識してコンパイルされます。
これらは両方とも独立して保存されますが、他の開発者に明確にしたい場合は、名前空間でラップすることをお勧めします。
特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。
ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。
ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。
あなたが一時的に会っていなかったとき。シーズン11-1を開始したチームであるニューヨークメッツは、日曜日の午後にフィラデルフィアで行われた最後の11試合の9試合目を失いました。
スティーブン・キングのアウトサイダーは、多くの点で先祖返りの小説であり、80年代の全盛期から引き裂かれたように見える生き物の特徴であり、おそらくセル以来の彼の最もパルプのような本ですが、今日の恐怖の中で間違いなく設立された作品です。表面上は、形を変えるペニーワイズのような子供たちの殺人者を中心としており、その最も暗い脅威は、封じ込められず、神経質に平凡なものよりも幻想的で打ち負かされません。
スティーブンユニバースビーチシティのエピソードが実行されるたびに、いくつかのクライマックスイベントが発生し、スティーブンユニバースのより広い神話に対する理解の一部が失われます。これはあなたが期待していたことですか?今日のエピソードは両方とも、容赦なくゆっくりと、シーズンの終盤の主要な部分を設定する決定的な結論に向かって進みます。そして、ロナウドは、静かな納屋が倒れているのを発見した夜中にスティーブンを捕まえるためにやって来ます。月に。
Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday
シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。
オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。
Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。
遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。
2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。
計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。