自动和静态变量的作用域仅限于定义它们的块。由于 Auto 变量是在堆栈中定义的,因此如果函数退出,堆栈将被销毁并释放自动变量的内存。但我在某处读到"但是,也可以使用此处给出的指针概念,通过指向变量所在的非常确切的内存位置来访问它们。这是对的吗?
此外,静态变量在数据部分中定义,因此它一直存在到程序结束。作用域位于定义它的块内。有什么方法可以从任何其他函数访问静态变量吗?另外,有什么方法可以从任何其他文件访问静态变量吗?
这是一个非常简单的例子:
void print_msg(const char* msg) {
printf("The message is: %sn", msg);
}
int main(void) {
char m[] = "Hello, world!";
print_msg(m);
}
在这里,m
是一个自动变量,它不在print_msg
的范围内。但print_msg
显然可以接触到它的价值。
不要将"范围"与"生命周期"混淆。变量的作用域是程序中变量名称可见(因此可以使用)的部分。值的生存期是程序执行期间存在值的时间段。范围是关于程序文本;它与汇编有关。生存期与程序执行有关。
正如你所说,静态变量存在于程序的整个生命周期中,即只要程序正在运行,分配给它们的内存就不会被破坏。因此,要在其范围之外访问这样的变量,我们可以通过指针传递指向该内存位置的指针。一个小例子来展示相同的
#include <stdio.h>
#include <stdlib.h>
int* func()
{
static int a = 0;
a++;
printf("a in func = %dn", a);
return &a;
}
int main()
{
int *p;
p = func();
printf("a in main from ptr : %dn", *p);
*p++;
p = func();
return 0;
}
正如您在示例中所看到的,func()
返回指向它声明的静态变量的指针,任何希望访问该变量a
的人都可以使用该指针。注意:我们只能这样做,因为静态变量的生命周期贯穿整个程序。现在,无论静态变量在不同的函数或不同的文件中,只要你能掌握指向该静态变量的指针,你就可以使用它。
现在来到自动变量的情况。
如果您运行上述程序将a
从static
更改为auto
会发生什么? 您将看到在编译时抛出警告warning: function returns address of local variable [-Wreturn-local-addr]
并在执行时得到一个segmentation fault
。 导致这种情况的原因是 auto 变量仅存在于其范围内,即只要函数func()
正在执行,变量a
就为自己分配了内存。函数退出后,为变量a
分配的内存将被释放,因此指针p
指向的值位于某个未分配的内存位置(导致分段错误)。
请注意,正如评论正确指出的那样,我在这里做一个假设,假设调用另一个函数的最简单情况不是问题所在。OP尚未确认或拒绝这一假设。例如,在 rici 的回答中讨论了这种情况。
自动变量的存在不仅存在于"其范围内(简化:只有同一封闭{}
之间的代码才能使用它们的标识符),它们还被限制在"期间"它们的"时间范围",即它们的生命周期(在函数中开始执行代码并完成其执行后简化)。可以通过指针访问变量的内存位置,该指针设置为它们的地址(这只能在它们的范围内,因为通过它们的标识符进行访问是必要的),只要它是在它们的生命周期内完成的,是的。
但是,如何从其他任何地方找到该指针呢?
也许通过(从其范围内部和生命周期内)写入全局变量。
但是哪个"其他"代码应该使用该值呢?(请记住,我在这里将函数调用放在一边)
这需要多线程/多任务/多任何内容。假设有一个中断服务例程在做这件事。它必须看到与变量作用域相同的地址空间,即没有内存管理单元妨碍一些虚拟内存魔法。对于许多多内容实现来说,情况并非如此,但不可否认的是,对于其中一些实现,所以让我们继续。
这个想象中的 ISR 必须确保它只在 auto 变量实际存在时(即在其生命周期内)访问它,否则它几乎会访问实际上是一个无意义的随机内存位置。这假设 ISR 实际上被允许/能够访问该内存。即使没有 MMU,也有一些实现可以/将具有例外。
这就引入了对同步机制的需求,例如信号量。
因此,在某些环境中这是可能的,但完全没有意义(仍然涉及全局变量),昂贵,难以理解,几乎不可能移植。(请记住,我在这里将函数调用放在一边)
静态变量类似。
在函数局部静态变量的情况下,它们至少会可靠地存在,但访问它们仍然需要以某种方式将指针值传输到其范围之外。对于实际上可以通过函数的返回值完成的静态变量,如 yashC 的答案所示。
对于理解为文件范围受限变量的"静态"变量,指针仍必须传输出文件范围。
这只会破坏文件范围限制变量的重点。但我可以想象某种访问权限方案,例如"这是金库的钥匙。小心处理。
正如本答案开头提到的,我将其他函数的调用放在一边。是的,离开函数作用域的最简单方法是调用另一个函数。如果另一个函数具有指针参数,则可以使用它对调用函数的自动变量进行读取访问和写入访问。这是 C 支持的按引用调用参数的正常情况.调用函数
还提供了另一种更简单的方法来读取访问调用函数的自动变量的值,尽管不是写访问,也不是实际访问自动变量本身,仅使用其值。这种方式是按值调用参数的简单机制,它甚至不需要指针。两种方式(按引用调用参数和按值调用参数)都可以方便地保证值在被调用函数的执行过程中不会更改。(这次我把多线程的情况放在一边,因为这在本答案的主要部分进行了讨论)。