Gdzie przechowywane są zmienne statyczne w C i C++?

W jakim segmencie (.BSS,Dane, inne) pliku wykonywalnego są statyczne zmienne przechowywane tak, że nie mają kolizji nazw? Na przykład:


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);
}                              }

Jeśli skompiluję oba pliki i połączę je z głównym, który wywołuje fooTest() i barTest wielokrotnie, instrukcje printf zwiększają się niezależnie. Ma to sens, ponieważ zmienne foo i bar są lokalne dla jednostki tłumaczenia.

Ale gdzie jest przydzielone miejsce do przechowywania?

Żeby było jasne, założenie jest takie, że masz toolchain, który wyświetli plik w formacie ELF. Tak więc, ja wierzę że tam mA być jakimś miejscem zarezerwowanym w pliku wykonywalnym dla tych zmiennych statycznych.
Dla celów dyskusji, Załóżmy, że używamy GCC toolchain.

16 answers

Gdzie statyka iść zależy od tego, czy są one inicjalizowane 0 czy nie. 0 inicjalizowane dane statyczne wchodzą w .BSS (Block Started by Symbol) , nie inicjowane 0 dane trafiają do .DANE

 112
Author: Don Neufeld,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 15:07:35

Gdy program jest ładowany do pamięci, jest zorganizowany w różne segmenty. Jednym z segmentów jest Segment danych . Segment danych jest dalej podzielony na dwie części:

Inicjalizowany segment danych: wszystkie dane globalne, statyczne i stałe są tutaj przechowywane.
Niezinicjalizowany segment danych(BSS): Wszystkie niezinicjalizowane dane są przechowywane w tym segmencie.

Oto schemat wyjaśniający to pojęcie:

Tutaj wpisz opis obrazka


oto bardzo dobry link wyjaśniający te pojęcia:

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

 91
Author: karn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-28 05:08:36

W rzeczywistości zmienną jest krotka (storage, scope, type, address, value):

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

Local scope może oznaczać lokalny dla jednostki translacyjnej( pliku źródłowego), funkcji lub bloku w zależności od tego, gdzie jest zdefiniowany. Aby zmienna była widoczna dla więcej niż jednej funkcji, na pewno musi znajdować się w obszarze DATA lub BSS (w zależności od tego, czy jest inicjalizowana jawnie, czy też nie). Jego zakres jest odpowiednio dostosowany do wszystkich funkcji lub funkcji w źródle plik.

 27
Author: yogeesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-20 19:38:30

Lokalizacja przechowywania danych będzie zależna od implementacji.

Jednak znaczenie static to "wewnętrzne powiązanie". Tak więc symbol wewnętrzny do jednostki kompilacji (foo.C, bar.c) i nie może być odwołany poza tą jednostką kompilacji. Więc nie może być kolizji nazw.

 20
Author: Seb Rose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 14:33:38

Nie wierzę, że dojdzie do kolizji. Użycie statyczne na poziomie pliku (funkcje Zewnętrzne) oznacza zmienną jako lokalną dla bieżącej jednostki kompilacji (pliku). Nigdy nie jest widoczny poza bieżącym plikiem, więc nigdy nie musi mieć nazwy.

Używanie statyki wewnątrz funkcji jest inne - zmienna jest widoczna tylko dla funkcji, tylko jej wartość jest zachowana przez wywołania do tej funkcji.

W efekcie, static robi dwie różne rzeczy w zależności od tego, gdzie się znajduje. W w innych przypadkach ogranicza widoczność zmiennej, aby zapobiec kolizjom przestrzeni nazw,

Powiedziawszy to, wierzę, że będzie przechowywany w danych, które mają tendencję do inicjalizacji zmiennej. BSS pierwotnie oznaczał byte-set- , który przechowywał zmienne, które nie zostały zainicjowane.

 11
Author: paxdiablo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 14:35:36

Jak znaleźć go samodzielnie z objdump -Sr

Aby naprawdę zrozumieć, co się dzieje, musisz zrozumieć relokację linkera. Jeśli nigdy tego nie dotykałeś, rozważ przeczytanie tego posta jako pierwsze.

Przeanalizujmy przykład Linuksa x86-64 ELF, aby zobaczyć go sami:

#include <stdio.h>

int f() {
    static int i = 1;
    i++;
    return i;
}

int main() {
    printf("%d\n", f());
    printf("%d\n", f());
    return 0;
}

Kompiluj z:

gcc -ggdb -c main.c

Dekompiluj kod za pomocą:

objdump -Sr main.o
  • -S dekompiluje kod z oryginalnym źródłem
  • -r pokazuje informacje o relokacji

Wewnątrz dekompilacji f widzimy:

 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

I .data-0x4 mówi, że przejdzie do pierwszego bajtu .data segmentu.

-0x4 jest tam, ponieważ używamy adresacji względnej RIP, a więc %rip w instrukcji i R_X86_64_PC32.

Jest to wymagane, ponieważ RIP wskazuje na następującą instrukcję , która zaczyna się 4 bajty po 00 00 00 00, co zostanie przeniesione. Wyjaśniłem to bardziej szczegółowo at: https://stackoverflow.com/a/30515926/895245

Następnie, jeśli zmienimy źródło na i = 1 i wykonamy tę samą analizę, wnioskujemy, że:

  • static int i = 0 idzie dalej .bss
  • static int i = 1 trwa .data
 8
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-14 14:48:26

To zależy od platformy i kompilatora, którego używasz. Niektóre Kompilatory przechowują bezpośrednio w segmencie kodu. Zmienne statyczne są zawsze dostępne tylko dla bieżącej jednostki tłumaczenia i nazwy nie są eksportowane, dlatego nazwa kolizji nigdy nie występuje.

 6
Author: trotterdylan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 14:33:42

W obszarze "globalny i statyczny":)

Istnieje kilka obszarów pamięci w C++

  • heap
  • darmowy sklep
  • stack
  • global & static
  • const

Zobacz tutaj aby uzyskać szczegółową odpowiedź na twoje pytanie

 5
Author: ugasoft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 14:43:35

Dane zadeklarowane w jednostce kompilacji trafią doBSS lub ... Dane wyjściowe tych plików. Dane inicjalizowane w BSS, niezainstalowane w danych.

Różnica między danymi statycznymi i globalnymi polega na włączeniu informacji o symbolach do pliku. Kompilatory zazwyczaj zawierają informacje o symbolach, ale zaznaczają tylko informacje globalne jako takie.

Linker szanuje te informacje. Informacja o symbolu dla zmiennych statycznych jest albo odrzucana, albo zniekształcana tak, że zmienne statyczne nadal mogą być odwołane w jakiś sposób (za pomocą opcji debugowania lub symbolu). W żadnym wypadku jednostki kompilacji nie mogą zostać naruszone, ponieważ linker rozwiązuje lokalne referencje jako pierwszy.

 5
Author: itj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:27:31

Statyczna zmienna przechowywana w segmencie danych lub segmencie kodu, jak wspomniano wcześniej.
Możesz być pewien, że nie zostanie on przydzielony na stos lub stertę.
Nie ma ryzyka kolizji, ponieważ słowo kluczowe static określa zakres zmiennej jako plik lub funkcję, w przypadku kolizji istnieje kompilator/linker, o którym można cię ostrzec.
Ładny przykład

 2
Author: Ilya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 15:00:20

Cóż to pytanie jest trochę za stare, ale ponieważ nikt nie wskazuje żadnych użytecznych informacji: Zobacz post przez 'mohit12379' wyjaśniający przechowywanie zmiennych statycznych o tej samej nazwie w tabeli symboli: http://www.geekinterview.com/question_details/24745

 2
Author: lukmac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-20 21:12:06

Próbowałem z objdump i gdb, oto wynik, co otrzymuję:

(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.

Oto wynik obiektu

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

To znaczy, że Twoje cztery zmienne znajdują się w sekcji data event o tej samej nazwie, ale z innym przesunięciem.

 2
Author: Dan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 17:43:41

Odpowiedź może bardzo dobrze zależeć od kompilatora, więc prawdopodobnie chcesz edytować swoje pytanie(mam na myśli, nawet pojęcie segmentów nie jest wymagane przez ISO C ani ISO C++). Na przykład w systemie Windows plik wykonywalny nie zawiera nazw symboli. Jeden 'foo' byłby przesunięty o 0x100, drugi być może o 0x2B0, a kod z obu jednostek tłumaczeniowych jest kompilowany znając przesunięcia dla" ich " foo.

 1
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 14:34:37

Oba będą przechowywane niezależnie, jednak jeśli chcesz wyjaśnić innym programistom, możesz chcieć je zawinąć w przestrzenie nazw.

 0
Author: Robert Gould,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 14:38:53

Tak (łatwo zrozumieć):

stos, sterta i dane statyczne

 0
Author: Yousha Aleayoub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-12 18:00:06

Wiesz już, że albo przechowuje się w bss (Block start by symbol), zwanym również niezainicjalizowanym segmentem danych, albo w zainicjalizowanym segmencie danych.

Weźmy prosty przykład

void main(void)
{
static int i;
}

Powyższa zmienna statyczna nie jest inicjalizowana , więc przechodzi do niezainicjalizowanego segmentu danych(bss).

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

I oczywiście zainicjalizowana przez 10, więc przechodzi do zainicjalizowanego segmentu danych.

 -1
Author: Anurag Bhakuni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-30 07:28:31