在哪个区段?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工具链。


当前回答

在“全局和静态”区域:)

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则不同——变量只对函数可见(无论是否是静态的),只是它的值在调用该函数时被保留。

实际上,静态的作用取决于它所处的位置。但是,在这两种情况下,变量的可见性都受到限制,可以在链接时轻松防止名称空间冲突。

话虽如此,我相信它将存储在DATA部分中,该部分往往具有初始化为非零值的变量。当然,这是一个实现细节,而不是标准所强制要求的东西——它只关心行为,而不是事情在幕后是如何完成的。

如何用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指向下面的指令,它在00 00 00 00 00之后4个字节开始,00 00 00 00将被重新定位。我已经在https://stackoverflow.com/a/30515926/895245上详细解释了这一点

然后,如果我们将源修改为i = 1,并进行同样的分析,我们得出:

静态int I = 0是。bss 静态int I = 1在。data上

答案很可能取决于编译器,所以您可能需要编辑您的问题(我的意思是,即使是段的概念也不是ISO C或ISO c++强制要求的)。例如,在Windows上,可执行文件不携带符号名。一个“foo”的偏移量是0x100,另一个可能是0x2B0,来自两个翻译单元的代码在编译时都知道“他们的”foo的偏移量。

它们都将被独立存储,但是如果您想让其他开发人员清楚地知道,您可能希望将它们包装在名称空间中。

静态数据的位置取决于它们是否为零初始化。零初始化的静态数据放入.BSS(由符号启动的块),非零初始化的数据放入.DATA