Где хранятся статические переменные в C и C ++? - PullRequest
159 голосов
/ 18 сентября 2008

В каком сегменте (.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.

Ответы [ 16 ]

2 голосов
/ 13 октября 2014

Я пробовал это с 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

Итак, ваши четыре переменные находятся в разделе данных под одним и тем же именем, но с другим смещением.

2 голосов
/ 21 марта 2011

Ну, этот вопрос слишком старый, но никто не указывает на полезную информацию: Проверьте сообщение от 'mohit12379', объясняющее хранилище статических переменных с тем же именем в таблице символов: http://www.geekinterview.com/question_details/24745

2 голосов
/ 18 сентября 2008

статическая переменная, хранящаяся в сегменте данных или сегменте кода, как упоминалось ранее.
Вы можете быть уверены, что он не будет размещен в стеке или куче.
Нет риска для столкновения, поскольку ключевое слово static определяет область действия переменной, являющейся файлом или функцией, в случае коллизии есть компилятор / компоновщик, чтобы предупредить вас.
Хороший пример

1 голос
/ 18 сентября 2008

Ответ может очень сильно зависеть от компилятора, поэтому вы, вероятно, захотите отредактировать свой вопрос (я имею в виду, что даже понятие сегментов не является обязательным ни в ISO C, ни в ISO C ++). Например, в Windows исполняемый файл не содержит имен символов. Один 'foo' будет смещен на 0x100, другой, возможно, на 0x2B0, и код из обоих модулей перевода будет скомпилирован с учетом смещений для "своего" foo.

0 голосов
/ 30 июня 2014

вы уже знаете, хранится ли он в bss (начало блока по символу), также называемом сегментом неинициализированных данных, или в сегменте инициализированных данных.

Давайте рассмотрим простой пример

void main(void)
{
static int i;
}

вышеуказанная статическая переменная не инициализирована, поэтому она переходит в неинициализированный сегмент данных (bss).

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

и, конечно, он инициализируется 10, поэтому он переходит в инициализированный сегмент данных.

0 голосов
/ 18 сентября 2008

они оба будут храниться независимо, однако, если вы хотите прояснить это другим разработчикам, вы можете заключить их в пространства имен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...