ตัวแปรสแตติกเก็บไว้ที่ไหนใน C และ C ++


180

ในส่วนใด (.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 เป็นโลคัลสำหรับหน่วยการแปล

แต่ที่เก็บข้อมูลจัดสรรอยู่ที่ไหน

เพื่อให้ชัดเจนข้อสันนิษฐานคือคุณมี toolchain ที่จะส่งออกไฟล์ในรูปแบบ ELF ดังนั้นผมเชื่อว่ามีมีที่จะสงวนพื้นที่บางส่วนในแฟ้มที่ปฏิบัติการได้สำหรับตัวแปรคงที่เหล่านั้น
สำหรับวัตถุประสงค์ในการสนทนาสมมติว่าเราใช้เครื่องมือห่วงโซ่ GCC


1
คนส่วนใหญ่บอกคุณว่าควรเก็บไว้ในส่วน. Data แทนที่จะตอบคำถามของคุณ: ตรงไหนในส่วน. Data และคุณจะหาที่ไหนได้บ้าง ฉันเห็นคุณทำเครื่องหมายคำตอบอยู่แล้วคุณจึงรู้วิธีค้นหาได้อย่างไร
lukmac

เหตุใดการกำหนดค่าเริ่มต้นและไม่ได้กำหนดไว้เริ่มต้นจะอยู่ในส่วนต่างๆ: linuxjournal.com/article/1059
mhk

1
หน่วยเก็บที่จัดสรรให้กับตัวแปรโกลบอล / สแตติกของคุณ ณ รันไทม์ไม่เกี่ยวข้องกับการจำแนกชื่อของมันซึ่งเกิดขึ้นระหว่างเวลาสร้าง / ลิงก์ หลังจากสร้างแฟ้มที่ปฏิบัติการได้แล้วจะไม่มีชื่ออีกแล้ว
valdo

2
คำถามนี้ไม่มีความหมายถูกสร้างขึ้นบนสมมติฐานที่ว่า "การชนกันของชื่อ" ของสัญลักษณ์ที่ไม่ได้ส่งออกเป็นสิ่งที่สามารถมีอยู่ได้ ความจริงที่ว่าไม่มีคำถามที่ถูกกฎหมายอาจอธิบายได้ว่าคำตอบบางคำนั้นน่ากลัวเพียงใด มันยากที่จะเชื่อว่ามีคนเพียงไม่กี่คนที่ได้รับสิ่งนี้
underscore_d

คำตอบ:


131

ในกรณีที่สถิตของคุณไปขึ้นอยู่กับว่าพวกเขาจะเป็นศูนย์เริ่มต้น ศูนย์เตรียมใช้ข้อมูลแบบคงที่ไปในการ.BSS (บล็อกเริ่มโดย Symbol) , ที่ไม่ใช่ศูนย์ที่เริ่มข้อมูลไปใน.DATA


50
โดย "non-0 initialized" คุณอาจหมายถึง "initialized แต่มีบางอย่างที่ไม่ใช่ 0" เพราะไม่มีสิ่งเช่นข้อมูลคงที่ "ไม่เริ่มต้น" ใน C / C ++ ทุกอย่างคงที่เป็นศูนย์เริ่มต้นโดยศูนย์
AnT

21
@ Don Neufeld: คำตอบของคุณไม่ตอบคำถามเลย ฉันไม่เข้าใจว่าทำไมจึงเป็นที่ยอมรับ เนื่องจากทั้ง 'foo' และ 'bar' ไม่ได้กำหนดค่าเริ่มต้นไว้ที่ 0 คำถามคือที่ที่จะวางตัวแปร static / global สองตัวที่มีชื่อเดียวกันใน. bbs หรือ. data
lukmac

ฉันใช้การใช้งานที่ข้อมูลสแตติกที่ถูกกำหนดค่าเริ่มต้นเป็นศูนย์อย่างชัดเจน.dataและข้อมูลสแตติกที่ไม่มี initializer เข้า.bssมา
MM

1
@MM ในกรณีของฉันไม่ว่าสมาชิกแบบคงที่จะไม่เริ่มต้น (เริ่มต้นโดยนัยถึง 0) หรือเริ่มต้นอย่างชัดเจนถึง 0 ในทั้งสองกรณีมันเพิ่มขึ้นในส่วน. BSS
cbinder

ข้อมูลนี้เป็นข้อมูลเฉพาะของไฟล์ที่เรียกทำงานบางประเภทหรือไม่ ฉันคิดว่าเนื่องจากคุณไม่ได้ระบุว่ามันใช้อย่างน้อยกับไฟล์ที่เรียกทำงานได้ของ ELF และ Windows PE แต่ประเภทอื่น ๆ ล่ะ?
Jerry Jeremiah

116

เมื่อโปรแกรมถูกโหลดลงในหน่วยความจำจะมีการจัดระเบียบเป็นกลุ่มที่แตกต่างกัน หนึ่งในส่วนที่เป็นส่วนข้อมูล ส่วนข้อมูลแบ่งย่อยออกเป็นสองส่วนเพิ่มเติม:

ส่วนข้อมูลเริ่มต้น : ข้อมูลส่วนกลางข้อมูลคงที่และค่าคงที่ทั้งหมดจะถูกเก็บไว้ที่นี่
ส่วนข้อมูลที่ไม่เริ่มต้น (BSS):ข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้นทั้งหมดจะถูกเก็บไว้ในส่วนนี้

นี่คือแผนภาพเพื่ออธิบายแนวคิดนี้:

ป้อนคำอธิบายรูปภาพที่นี่


นี่เป็นลิงค์ที่ดีมากที่อธิบายแนวคิดเหล่านี้:

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


คำตอบข้างต้นบอกว่า 0 เริ่มต้นเข้าสู่ BSS ค่าเริ่มต้น 0 หมายถึงไม่กำหนดค่าเริ่มต้นหรือ 0 ต่อ se หรือไม่ ถ้ามันหมายถึง 0 ต่อ se ฉันคิดว่าคุณควรรวมไว้ในคำตอบของคุณ
Viraj

ข้อมูลคงที่จะไม่ถูกเก็บไว้ในส่วน. data แต่อยู่ในส่วน .const ของส่วนข้อความ
user10678

แทนที่จะเป็นแบบนี้ (" ส่วนข้อมูลเริ่มต้น : ข้อมูลส่วนกลางข้อมูลคงที่และค่าคงที่ทั้งหมดจะถูกเก็บไว้ที่นี่ส่วนข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้น(BSS) : ข้อมูลทั้งหมดที่ไม่ได้ถูกจัดเก็บไว้ในส่วนนี้") ฉันคิดว่าส่วนข้อมูลเริ่มต้น : ตัวแปรโกลบอล & สแตติกทั้งหมดที่ถูกกำหนดค่าเริ่มต้นให้เป็นค่าที่ไม่เป็นศูนย์และข้อมูลคงที่ทั้งหมดจะถูกเก็บไว้ที่นี่ส่วนของข้อมูลเริ่มแรก (BSS) : ตัวแปรโกลบอลและสแตติกทั้งหมดที่ไม่ได้ถูกเตรียมข้อมูลเบื้องต้นถึงศูนย์จะถูกเก็บไว้ในส่วนนี้ ")
Gabriel Staples

โปรดทราบว่าเท่าที่ฉันเข้าใจ "ข้อมูลที่เตรียมใช้งานแล้ว" อาจประกอบด้วยตัวแปร และ ค่าเริ่มต้นที่ยังคงอยู่ บนไมโครคอนโทรลเลอร์ (เช่น: STM32) ตัวแปรเริ่มต้นจะถูกเก็บไว้ตามค่าเริ่มต้นในหน่วยความจำแฟลชและคัดลอกไปยัง RAM เมื่อเริ่มต้นและค่าคงที่เริ่มต้นจะถูกปล่อยไว้และตั้งใจจะอ่านจากแฟลชเท่านั้นพร้อมกับข้อความซึ่งมี โปรแกรมเองและเหลืออยู่ในFlash เท่านั้น
Gabriel Staples

ดังนั้นสิ่งที่ฉันรวบรวมจากแผนภาพนี้คือตัวแปรที่เป็นแบบโกลบอลหรือแบบสแตติก (เนื่องจากตัวแปรแบบสแตติกทำหน้าที่เหมือนกับตัวแปรแบบโกลบอลในช่วงเวลา) ไม่ได้อยู่บนฮีปหรือสแต็ก แต่มีการจัดสรรในหน่วยความจำแยกจากกัน นั่นถูกต้องใช่ไหม? ฉันคิดว่าฉันสามารถดูที่สคริปต์ลิงเกอร์ STM32 อีกครั้งเพื่อศึกษาการจัดสรรหน่วยความจำได้อีกด้วย
Gabriel Staples

32

อันที่จริงแล้วตัวแปรคือ tuple (หน่วยเก็บ, ขอบเขต, ประเภท, ที่อยู่, ค่า):

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

ขอบเขตโลคัลอาจหมายถึงโลคัลสำหรับหน่วยการแปล (ไฟล์ต้นฉบับ) ฟังก์ชันหรือบล็อกขึ้นอยู่กับตำแหน่งที่กำหนด ในการทำให้ตัวแปรมองเห็นได้มากกว่าหนึ่งฟังก์ชั่นจะต้องอยู่ในพื้นที่ข้อมูลหรือ BSS อย่างแน่นอน (ขึ้นอยู่กับว่ามีการกำหนดค่าเริ่มต้นอย่างชัดเจนหรือไม่ตามลำดับ) จากนั้นจะถูกกำหนดขอบเขตตามฟังก์ชั่นทั้งหมดหรือฟังก์ชั่นภายในไฟล์ต้นฉบับ


21

ที่เก็บข้อมูลจะขึ้นอยู่กับการนำไปใช้

อย่างไรก็ตามความหมายของสแตติกคือ "การเชื่อมโยงภายใน" ดังนั้นสัญลักษณ์ดังกล่าวจะอยู่ภายในหน่วยการรวบรวม (foo.c, bar.c) และไม่สามารถอ้างอิงได้นอกหน่วยการรวบรวมนั้น ดังนั้นจึงไม่มีการชนกันของชื่อ


ไม่ keyworld แบบสแตติกมีความหมายมากเกินไป: ในกรณีเช่นนี้สแตติกคือตัวดัดแปลงหน่วยเก็บข้อมูลไม่ใช่ตัวดัดแปลงลิงก์
ugasoft

4
ugasoft: สถิตนอกฟังก์ชั่นเป็นตัวดัดแปลงการเชื่อมโยงภายในเป็นตัวดัดแปลงการจัดเก็บข้อมูลที่จะต้องไม่มีการปะทะกันที่จะเริ่มต้นด้วย
wnoise

12

ในพื้นที่ "global และ static" :)

มีพื้นที่หน่วยความจำหลายแห่งใน 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

ฉันไม่เชื่อว่าจะมีการปะทะกัน การใช้สแตติกที่ระดับไฟล์ (ฟังก์ชันภายนอก) ทำเครื่องหมายตัวแปรว่าเป็นโลคัลกับหน่วยการรวบรวมปัจจุบัน (ไฟล์) ไฟล์นี้จะไม่ปรากฏภายนอกไฟล์ปัจจุบันดังนั้นจึงไม่จำเป็นต้องมีชื่อที่สามารถใช้ภายนอกได้

การใช้สแตติกภายในฟังก์ชั่นจะแตกต่างกัน - ตัวแปรสามารถมองเห็นได้เฉพาะกับฟังก์ชั่น (ไม่ว่าจะคงที่หรือไม่) มันเป็นเพียงค่าของมันจะถูกเก็บไว้ในระหว่างการโทรไปยังฟังก์ชั่นนั้น

ผลคงที่ทำสองสิ่งที่แตกต่างกันขึ้นอยู่กับว่ามันอยู่ที่ไหน อย่างไรก็ตามในทั้งสองกรณีการมองเห็นตัวแปรนั้น จำกัด ในลักษณะที่คุณสามารถป้องกันการปะทะของ namespace เมื่อทำการเชื่อมโยง

ต้องบอกว่าฉันเชื่อว่ามันจะถูกเก็บไว้ในDATAส่วนซึ่งมีแนวโน้มที่จะมีตัวแปรที่เริ่มต้นเป็นค่าอื่นที่ไม่ใช่ศูนย์ แน่นอนว่านี่คือรายละเอียดการนำไปปฏิบัติไม่ใช่สิ่งที่ได้รับคำสั่งจากมาตรฐาน แต่เป็นเรื่องของพฤติกรรมเท่านั้นไม่ใช่สิ่งที่ทำภายใต้ปก


1
@paxdiablo: คุณได้กล่าวถึงตัวแปรสแตติกสองประเภท บทความใดในบทความนี้ ( en.wikipedia.org/wiki/Data_segment ) ที่อ้างถึง ส่วนข้อมูลยังเก็บตัวแปรทั่วโลก (ซึ่งตรงข้ามกับธรรมชาติกับตัวแปรแบบคงที่) So, how does a segment of memory (Data Segment) store variables that can be accessed from everywhere (global variables) and also those which have limited scope (file scope or function scope in case of static variables)?
Lazer

@ eSKay มันเกี่ยวกับการมองเห็น อาจมีสิ่งต่าง ๆ ที่เก็บไว้ในเซ็กเมนต์ซึ่งเป็นโลคัลสำหรับหน่วยการคอมไพล์ส่วนอื่น ๆ ที่สามารถเข้าถึงได้อย่างสมบูรณ์ ตัวอย่างหนึ่ง: คิดถึงแต่ละหน่วยโฆษณาที่สนับสนุนบล็อกในส่วนข้อมูล มันรู้ว่าทุกอย่างอยู่ในบล็อกนั้น นอกจากนี้ยังเผยแพร่ที่อยู่ของสิ่งเหล่านั้นในบล็อกที่ต้องการให้หน่วยคอมพ์อื่นสามารถเข้าถึงได้ ตัวเชื่อมโยงสามารถแก้ไขที่อยู่เหล่านั้นได้ในเวลาลิงก์
paxdiablo

11

วิธีค้นหาด้วยตัวเองด้วย 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 แสดงข้อมูลการย้ายถิ่นฐาน

ภายใน decompilation ของ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 ญาติอยู่ดังนั้นในการเรียนการสอนและ%ripR_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


6

ขึ้นอยู่กับแพลตฟอร์มและคอมไพเลอร์ที่คุณใช้ คอมไพเลอร์บางตัวเก็บไว้ในส่วนรหัสโดยตรง ตัวแปรคงที่สามารถเข้าถึงหน่วยการแปลปัจจุบันเท่านั้นและไม่ได้ส่งออกชื่อดังนั้นการชนกันของชื่อเหตุผลจะไม่เกิดขึ้น


5

ข้อมูลที่ประกาศในหน่วยการคอมไพล์จะเข้าไปใน. BSS หรือ. Data ของเอาต์พุตไฟล์นั้น ข้อมูลเริ่มต้นใน BSS ซึ่งไม่มีข้อมูลใน DATA

ความแตกต่างระหว่างข้อมูลสแตติกและโกลบอลมาจากการรวมข้อมูลสัญลักษณ์ไว้ในไฟล์ คอมไพเลอร์มีแนวโน้มที่จะรวมข้อมูลสัญลักษณ์ แต่ทำเครื่องหมายข้อมูลทั่วโลกเช่นนี้

ตัวเชื่อมโยงเคารพข้อมูลนี้ ข้อมูลสัญลักษณ์สำหรับตัวแปรแบบสแตติกจะถูกยกเลิกหรือมีการพันกันเพื่อให้ตัวแปรแบบสแตติกยังคงสามารถอ้างอิงได้ในบางวิธี (ด้วยตัวเลือกการดีบักหรือสัญลักษณ์) หน่วยการรวบรวมจะไม่ได้รับผลกระทบในกรณีใดตัวเชื่อมโยงจะแก้ไขการอ้างอิงในเครื่องก่อน


3

ฉันลองกับ 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 <printf@plt>
   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 <printf@plt>
   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

ดังนั้นสี่ตัวแปรของคุณจะอยู่ในเหตุการณ์ส่วนข้อมูลชื่อเดียวกัน แต่มีออฟเซ็ตต่างกัน


มีมากกว่านั้นอีกมาก แม้แต่คำตอบที่มีอยู่ก็ยังไม่สมบูรณ์ เพียงพูดถึงอย่างอื่น: ชาวกระทู้
Adriano Repetti

2

ตัวแปรสแตติกเก็บไว้ในส่วนข้อมูลหรือส่วนรหัสตามที่กล่าวไว้ก่อนหน้า
คุณสามารถมั่นใจได้ว่ามันจะไม่ถูกจัดสรรในกองหรือกอง
ไม่มีความเสี่ยงสำหรับการชนกันเนื่องจากstaticคำหลักกำหนดขอบเขตของตัวแปรที่จะเป็นไฟล์หรือฟังก์ชั่นในกรณีที่มีการชนกันจะมีคอมไพเลอร์ / ลิงเกอร์ที่จะเตือนคุณเกี่ยวกับ
เป็นตัวอย่างที่ดี


2

คำถามนี้ค่อนข้างเก่าเกินไป แต่เนื่องจากไม่มีใครชี้ให้เห็นข้อมูลที่เป็นประโยชน์ใด ๆ : ตรวจสอบการโพสต์โดย 'mohit12379' เพื่ออธิบายการจัดเก็บตัวแปรคงที่ที่มีชื่อเดียวกันในตารางสัญลักษณ์: http://www.geekinterview.com/question_details/ 24745


1

คำตอบอาจขึ้นอยู่กับคอมไพเลอร์ดังนั้นคุณอาจต้องการแก้ไขคำถามของคุณ (ฉันหมายถึงแม้แนวคิดเรื่องเซ็กเมนต์จะไม่ได้รับคำสั่งจาก ISO C หรือ ISO C ++) ตัวอย่างเช่นใน Windows โปรแกรมที่เรียกใช้ไม่ได้มีชื่อสัญลักษณ์ หนึ่ง 'foo' จะชดเชย 0x100 ส่วนอีก 0x2B0 และรหัสจากหน่วยการแปลทั้งสองจะถูกคอมไพล์โดยรู้ว่าออฟเซ็ตสำหรับ "foo" ของพวกเขา


0

พวกเขาทั้งคู่จะถูกเก็บไว้อย่างอิสระอย่างไรก็ตามหากคุณต้องการให้ชัดเจนกับนักพัฒนาคนอื่น ๆ คุณอาจต้องการห่อไว้ในเนมสเปซ


-1

คุณรู้อยู่แล้วว่ามันเก็บไว้ใน bss (บล็อกเริ่มด้วยสัญลักษณ์) หรือที่เรียกว่าเป็นส่วนข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้นหรือในส่วนของข้อมูลเริ่มต้น

ลองยกตัวอย่างง่ายๆ

void main(void)
{
static int i;
}

ตัวแปรสแตติกข้างต้นไม่ได้ถูกเตรียมใช้งานดังนั้นจึงไปยังส่วนข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้น (bss)

void main(void)
{
static int i=10;
}

และแน่นอนว่ามันเริ่มต้นด้วย 10 เพื่อไปยังส่วนของข้อมูลที่เริ่มต้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.