是否可以在声明它的函数之外访问静态局部变量



对于在 C 函数中定义的静态变量,如下所示:

int f1()
{
static int var2 = 42;
var2++;
printf("var2=%dn", var2);
}

var2将存储在.data段中(因为它被显式初始化为42,这要归功于@busybee指出这一点):

0000000000004014 l     O .data  0000000000000004              var2.2316

如果我没有显式初始化它或将其初始化为0var2将存储在.bss段中):

000000000000401c l     O .bss   0000000000000004              var2.2316

var2有两个方面:

  • 它的生命周期与整个程序相同。
  • 但其范围仅限于f1()以内。

bss部分适用于未初始化的全局数据。 而data部分用于初始化的全局数据。var2生活在bss,所以从某种意义上说,它必须是全球性的。

我认为var2只能在f1()内访问的原因只是编译器放置的一些语法规则。如果我们遍历bss部分,则必须可以从f1()外部访问var2。我说的对吗?谢谢。

好吧,你有对内存的原始访问权限,所以世界是你的牡蛎,但它们有限的访问范围正是使用静态局部变量的全部意义所在。

它们是具有受控访问权限的全局状态,因此您可以应用本地推理。

如果您可以从外部访问它们,那么本地推理就会消失。在这一点上,人们应该思考:为什么不直接使用常规全局?

以下是黑客的东西,除了其他答案,不是从语言律师的角度。

我认为var2只能在f1()内访问的原因只是编译器放置的一些语法规则。

挑剔地说,只有当编译器符合标准时,这才是真的。它是定义规则的标准。技术术语是"范围"。

如果我们遍历bss部分,则必须从 f1() 外部访问var2。我说的对吗?

是的。只要程序运行,该部分就存在。您可以使用指针进入此部分并访问存在在那里的任何变量。当然,这也适用于data部分。

您还可以使用指针访问任何动态变量。通常,这些是在堆栈上分配的。但是,要掌握特定值可能非常棘手。

但所有这些访问至少都是特定于应用程序的、编译器和系统相关的。你可能会违反一些规则。但原则上,没有什么可以阻止你。


bss部分用于未初始化的全局数据。而data部分用于初始化的全局数据。

仅当您的意思是"显式初始化为非零值"时,这才是正确的。

这两个部分在main()开始之前进行初始化。bss中的所有值都归零,data中的所有值都设置为其非零值。显式初始化为零值的变量通常会在bss中分配。

存在单独节的原因是为了节省可执行文件中的空间。bss部分通常不存储,仅定义。存储一大堆零是没有意义的,启动代码会将整个部分归零。

var2 生活在 bss 中

var2不存在于bss段,而是存在于data段中,如切口所示。您的var初始化为 42,这显然不为零。

定义了

两个执行环境:独立式和托管式。在 这两种情况,当指定的 C 函数 由执行环境调用。具有静态存储的所有对象 持续时间应在之前初始化(设置为其初始值) 程序启动。这种初始化的方式和时间是 否则未指定。程序终止将控制权返回给 执行环境。

声明

其标识符而不声明存储类的对象 规范 _Thread_local,无论是外部链接还是内部链接,或者存储类说明符 static,都具有静态存储持续时间。其 生命周期是程序及其存储值的整个执行 在程序启动之前仅初始化一次。

您的静态局部变量具有静态存储持续时间,并将在程序执行开始之前(即在调用main之前)进行初始化。您可以通过指向它的指针访问它。指针只能通过调用函数来获取。

int *func()
{
static int x;
return &x
}

var2 有两个方面:

  • 它的生命周期与整个程序相同。
  • 但它的范围仅限于f1()以内。

是和不是。 生存期是对象的属性。 范围是标识符(名称)的属性。var2的范围是从它在f1()中的声明到函数的结束,是关于源的区域,其中该名称标识所讨论的对象。 另一方面,在该作用域内由var2标识的对象的生存期与整个程序的生存期相同,是关于对象本身的。

bss 部分用于未初始化的全局数据。虽然数据部分用于初始化的全局数据。var2 存在于 bss 中,因此它在某种意义上必须是全局的。

尝试从实现细节推断语言语义时要非常小心。 很容易弄错,很难在所有细节上都做对。 在这种特殊情况下,所讨论的对象是全局的,因为它的生存期与你已经知道的整个程序的生存期相同。

为了记录,"全球"不是一个C语言术语。 当人们在C上下文中说"全局变量"时,他们通常意味着一个更恰当地描述为具有外部链接的变量,它必然标识具有静态存储持续时间(即程序的整个执行)的对象。 这不是你在var2的情况下看到的。

我认为var2只能在f1()内访问的原因只是编译器放置的一些语法规则

或多或少是的。 只能在该名称的范围内按名称访问对象。 这是C语言的语义规则之一。 它基本上是"范围"的定义。

如果我们遍历bss部分,则必须可以从f1()外部访问var2。我说的对吗?

您建议如何"遍历bss部分"? 首先,这是某些可执行文件格式的特征,而不是程序的运行时特征。 但也许你的意思是"遍历内存",但即便如此,C 也没有定义一种方法来做到这一点。

话虽如此,例如,如果f1()通过 out 变量发布了指向其var2变量的指针,则该指针确实可以在函数外部用于访问该对象。 像这样,例如:

int f1(int **pptr) {
static int var2 = 42;
*pptr = &var2;
var2++;
return printf("var2=%dn", var2);
}
// ...
void other_function() {
int *ptr;
int res = f1(&ptr);
printf("%dn", *ptr);
}

最新更新