我正在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中变量名称一部分的字符,即.
,$
,%
,{{1} }等
答案 0 :(得分:3)
局部静态变量的名称从何而来?是进程ID还是随机数?
在gcc的langhooks.c中,默认的set_decl_assembler_name
钩子实现(直接用于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文件中的声明),该标识符均应保证是不同的。这足以确保不同的作用域是否使用具有相同名称的局部静态变量,它们在汇编代码和目标代码中将具有不同的符号名称。
global_static
中没有无效字符的事实是否意味着我可以在另一个文件中进行extern static int global_static;
并读取global_static
?
不。一方面,结合使用extern
和static
是非法的,因为它们给变量带来了相互矛盾的联系。请注意,static
在C中有两个完全不同的含义:在函数内部,这意味着变量具有静态存储持续时间。在函数外部,这意味着变量或函数具有内部链接。 (不是函数本地变量的变量始终具有静态存储持续时间。)
因此,从C语言的角度来看,static
上的global_static
意味着该变量具有内部链接,这意味着它永远不会被视为与任何其他翻译单元中的任何变量相同的变量,因此无法从另一个* .c文件直接访问它。在转换为ELF对象或其他常见对象格式时,可以通过将变量的符号设置为“局部”符号而不是“全局”符号来实现。链接可执行文件或加载动态库时,全局符号可以满足另一个对象中未定义的符号,而本地符号则永远不能满足。
请注意,nm
工具会为全局符号打印大写的符号类型字母,为局部符号打印小写的符号类型字母,因此输出中变量旁边的d
表示它们都是本地符号,不能可能被其他对象直接使用。
答案 1 :(得分:2)
这是翻译单元(源/目标文件)中的唯一标识符,因此具有不同本地范围的同名static
将不会引用同一对象。
否。在程序集/目标文件中未标记为全局的符号不能在链接时用于解析其他文件中的引用。他们被忽略了。 (d
中的小写nm
表示它是局部符号,而不是全局符号。)在同一程序集/对象文件中,不能同时拥有外部和静态对象的C源代码级规则在文件作用域具有相同标识符的情况将其排除。