c - GCC 中静态变量的符号是如何命名的?

标签 c gcc static

我正在 C 中试验静态全局变量。我尝试了这段代码并在其上运行了 nm:

#include <stdio.h>

static int global_static = 12345;

int main(void)
{
    static int local_static = 12345;
    printf("%d\n", global_static);
    printf("%d\n", local_static);
    return 0;
}

这是 nm 输出的片段:

00004020 d global_static
00004024 d local_static.1905
000011a9 T main

我有两个问题:

  • 局部静态变量的名称从何而来?是进程ID还是随机数?

  • global_static 中没有无效字符这一事实是否意味着我可以在另一个文件中执行 extern static int global_static; 并读取 global_static ?

当我说无效字符时,我指的是不能作为 C 变量名一部分的字符,即 .$% #

最佳答案

Where does the name for the local static variable come from? Is it a process ID or a random number?

在gcc的langhooks.c中,默认的set_decl_assembler_name钩子(Hook)实现(C语言直接使用)contains :

  /* By default, assume the name to use in assembly code is the same
     as that used in the source language.  (That's correct for C, and
     GCC used to set DECL_ASSEMBLER_NAME to the same value as
     DECL_NAME in build_decl, so this choice provides backwards
     compatibility with existing front-ends.  This assumption is wrapped
     in a target hook, to allow for target-specific modification of the
     identifier.
     Can't use just the variable's own name for a variable whose scope
     is less than the whole compilation.  Concatenate a distinguishing
     number - we use the DECL_UID.  */
  if (TREE_PUBLIC (decl) || DECL_FILE_SCOPE_P (decl))
    id = targetm.mangle_decl_assembler_name (decl, DECL_NAME (decl));
  else
    {
      const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
      char *label;
      ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
      id = get_identifier (label);
    }

还有 comment on the macro DECL_UID说:

/* Every ..._DECL node gets a unique number.  */

所以这个数字是 gcc 发明的一些标识符,保证在翻译单元中看到的每个声明都是不同的(包括 #include-d 文件中的声明)。这足以确保如果不同的范围使用具有相同名称的局部静态变量,它们在汇编代码和目标代码中将具有不同的错位符号名称。

Does the fact that global_static has no invalid characters in it imply that I could do extern static int global_static; in another file and read global_static?

没有。一方面,将 externstatic 结合使用是非法的,因为它们会给变量提供相互冲突的链接。请注意,static 在 C 中有两个完全不同的含义:在函数内部,它表示变量具有静态存储持续时间。在函数外部,表示变量或函数具有内部链接。 (不是函数本地的变量始终具有静态存储持续时间。)

所以从 C 语言的角度来看,global_static 上的 static 意味着该变量具有内部链接,这意味着它永远不会被视为与任何其他翻译单元中的任何内容,因此无法从另一个 *.c 文件直接访问它。当转换为 ELF 对象或其他常见对象格式时,这是通过使变量的符号成为“本地”符号而不是“全局”符号来完成的。当链接可执行文件或加载动态库时,全局符号可以满足来自另一个对象的 undefined symbol ,但局部符号永远不会。

注意 nm 工具为全局符号打印大写符号类型字母,为局部符号打印小写符号类型字母,因此输出中变量旁边的 d 表示两者都是本地符号,不可能被其他对象直接使用。

关于c - GCC 中静态变量的符号是如何命名的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56498960/

相关文章:

c - 编译 gcc-2.7.2.3 时出错

Java:无法访问静态单例方法

c - 是否有标准 mtx_t 'invalid' 状态?

java - 我怎样才能对 main 有多个定义?

c - 双链表中在末尾插入一个节点并在开头删除一个节点

c++ - zlib 的奇怪分析结果

c - 函数类型 "extern __declspec(dllimport) INT __cdecl"在 C/C++ 或 SWIG 中有意义吗?

gcc - 在创世纪2.3中通过编译Makefile形成的.c文件产生错误

ios - xCode 4.3 静态库跨项目引用

c++ - 不理解静态 boolean 行为