静的変数はCおよびC ++のどこに格納されていますか?

184
Benoit 2008-09-19 04:29.

実行可能ファイルのどのセグメント(.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ツールチェーンを使用すると仮定しましょう。

15 answers

134
Don Neufeld 2008-09-19 05:07.

静力学がどこに行くかは、それらがゼロで初期化されているかどうかによって異なりますゼロ初期化された静的なデータになります(ブロックは、シンボルによって開始).bssセクション、非ゼロ初期化されたデータは、に行く.DATA

119
karn 2012-07-28 19:08.

プログラムがメモリにロードされると、さまざまなセグメントに編成されます。セグメントの1つはDATAセグメントです。データセグメントはさらに2つの部分に分割されます。

初期化されたデータセグメント:すべてのグローバル、静的、および定数データが​​ここに格納されます。
初期化されていないデータセグメント(BSS):初期化されていないすべてのデータがこのセグメントに格納されます。

この概念を説明する図を次に示します。


これらの概念を説明する非常に良いリンクがあります:

http://www.inf.udec.cl/~leo/teoX.pdf

32
yogeesh 2008-09-21 09:38.

実際、変数はタプル(ストレージ、スコープ、タイプ、アドレス、値)です。

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領域にある必要があります(それぞれ明示的に初期化されているかどうかによって異なります)。次に、ソースファイル内のすべての関数または関数のいずれかに応じてスコープが設定されます。

21
Seb Rose 2008-09-19 04:33.

データの保存場所は実装によって異なります。

ただし、静的の意味は「内部リンケージ」です。したがって、シンボルはコンパイルユニット(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
12
ugasoft 2008-09-19 04:43.

「グローバルおよび静的」領域で:)

C ++にはいくつかのメモリ領域があります。

  • ヒープ
  • 無料ストア
  • スタック
  • グローバル&スタティック
  • const

あなたの質問に対する詳細な答えについては、ここを参照してください:

以下は、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.
12
paxdiablo 2008-09-19 04:35.

衝突はないと思います。ファイルレベル(関数外)でstaticを使用すると、変数が現在のコンパイル単位(ファイル)に対してローカルとしてマークされます。現在のファイルの外部に表示されることはないため、外部で使用できる名前を付ける必要はありません。

関数内で静的を使用することは異なります-変​​数は関数にのみ表示され(静的かどうかに関係なく)、その値はその関数の呼び出し間で保持されます。

実際、staticは、それがどこにあるかに応じて2つの異なることを行います。では、両方しかし例、変数の可視性は、リンク時に使用すると、簡単に名前空間の衝突を防ぐことができますように制限されています。

そうは言ってDATAも、ゼロ以外の値に初期化される変数を持つ傾向があるセクションに格納されると思います。もちろん、これは実装の詳細であり、標準で義務付けられているものではありません。これは、動作のみを考慮し内部でどのように行われるかは考慮しません。

8
Yousha Aleayoub 2018-03-13 01:24.

これが(理解しやすい)方法です:

6
trotterdylan 2008-09-19 04:33.

使用しているプラ​​ットフォームとコンパイラによって異なります。一部のコンパイラは、コードセグメントに直接格納します。静的変数は常に現在の変換ユニットにのみアクセス可能であり、名前はエクスポートされないため、名前の衝突が発生することはありません。

5
itj 2008-09-19 10:27.

コンパイル単位で宣言されたデータは、そのファイルの.BSSまたは.Data出力に送られます。BSSで初期化されたデータ、DATAで初期化されていないデータ。

静的データとグローバルデータの違いは、ファイルにシンボル情報が含まれていることです。コンパイラはシンボル情報を含める傾向がありますが、グローバル情報をそのようにマークするだけです。

リンカはこの情報を尊重します。静的変数のシンボル情報は破棄またはマングルされるため、静的変数は引き続き何らかの方法で参照できます(デバッグまたはシンボルオプションを使用)。どちらの場合も、リンカーが最初にローカル参照を解決するため、コンパイル単位が影響を受けることはありません。

3
Dan 2014-10-14 07:43.

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つの変数は、同じ名前でオフセットが異なるデータセクションイベントにあります。

2
Ilya 2008-09-19 05:00.

前述のように、データセグメントまたはコードセグメントに格納されている静的変数。
スタックまたはヒープに割り当てられないことを確認できます。キーワードは変数のスコープをファイルまたは関数として定義するため、
衝突のリスクはありません。static衝突の場合は、警告するコンパイラ/リンカーがあります。
良い例

2
lukmac 2011-03-21 11:12.

この質問は少し古すぎますが、有用な情報を誰も指摘していないため、シンボルテーブルに同じ名前の静的変数が格納されていることを説明する「mohit12379」による投稿を確認してください。 http://www.geekinterview.com/question_details/24745

1
MSalters 2008-09-19 04:34.

答えはコンパイラに非常に依存している可能性があるため、質問を編集することをお勧めします(つまり、セグメントの概念でさえ、ISOCまたはISOC ++では必須ではありません)。たとえば、Windowsでは、実行可能ファイルはシンボル名を持っていません。一方の「foo」はオフセット0x100で、もう一方はおそらく0x2B0であり、両方の変換ユニットからのコードは、「それらの」fooのオフセットを認識してコンパイルされます。

0
Robert Gould 2008-09-19 04:38.

これらは両方とも独立して保存されますが、他の開発者に明確にしたい場合は、名前空間でラップすることをお勧めします。

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

ジェイ・ブルースはどうやら子供を妊娠することによってメッツから離れて取引されていることを祝った

ジェイ・ブルースはどうやら子供を妊娠することによってメッツから離れて取引されていることを祝った

あなたが一時的に会っていなかったとき。シーズン11-1を開始したチームであるニューヨークメッツは、日曜日の午後にフィラデルフィアで行われた最後の11試合の9試合目を失いました。

スティーブンキングのアウトサイダーはトランプ時代のそれです

スティーブンキングのアウトサイダーはトランプ時代のそれです

スティーブン・キングのアウトサイダーは、多くの点で先祖返りの小説であり、80年代の全盛期から引き裂かれたように見える生き物の特徴であり、おそらくセル以来の彼の最もパルプのような本ですが、今日の恐怖の中で間違いなく設立された作品です。表面上は、形を変えるペニーワイズのような子供たちの殺人者を中心としており、その最も暗い脅威は、封じ込められず、神経質に平凡なものよりも幻想的で打ち負かされません。

スティーブンユニバースは、強烈な内部エピソードのペアで、それ自体のバックストーリーをさりげなく粉砕します

スティーブンユニバースは、強烈な内部エピソードのペアで、それ自体のバックストーリーをさりげなく粉砕します

スティーブンユニバースビーチシティのエピソードが実行されるたびに、いくつかのクライマックスイベントが発生し、スティーブンユニバースのより広い神話に対する理解の一部が失われます。これはあなたが期待していたことですか?今日のエピソードは両方とも、容赦なくゆっくりと、シーズンの終盤の主要な部分を設定する決定的な結論に向かって進みます。そして、ロナウドは、静かな納屋が倒れているのを発見した夜中にスティーブンを捕まえるためにやって来ます。月に。

ディズニーワールドの旅行のヒントを教えてください

ディズニーワールドの旅行のヒントを教えてください

「光が触れるものはすべて私たちの王国です。」今週のHackYour Cityでは、1つのテーマパークを取り上げます。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language