我有以下代码
int main()
{
static int x = 8;
{
static int x = 9;
}
printf("%d",x);
}
O / P-8
我怀疑,根据规则,静态变量只创建一次并保留在内存中。如果名称为x的变量在内存中保留,那么我怎样才能创建一个新变量。
请清楚我的怀疑。我经历了谷歌,但它是如何完成的,我想要的是C编程。如何编译器识别变量以及它如何存储在内存中。
Ť
答案 0 :(得分:2)
objdump
的反汇编输出可能会给你一些关于编译器(在这种情况下为gcc
)如何处理这种情况的提示:
$ objdump -d a.out
...
000000000040050c <main>:
40050c: 55 push %rbp
40050d: 48 89 e5 mov %rsp,%rbp
400510: 8b 05 fa 03 20 00 mov 0x2003fa(%rip),%eax # 600910 <x.2163>
400516: 89 c6 mov %eax,%esi
400518: bf fc 05 40 00 mov $0x4005fc,%edi
40051d: b8 00 00 00 00 mov $0x0,%eax
400522: e8 b9 fe ff ff callq 4003e0 <printf@plt>
400527: 8b 05 e7 03 20 00 mov 0x2003e7(%rip),%eax # 600914 <x.2162>
40052d: 89 c6 mov %eax,%esi
40052f: bf fc 05 40 00 mov $0x4005fc,%edi
400534: b8 00 00 00 00 mov $0x0,%eax
400539: e8 a2 fe ff ff callq 4003e0 <printf@plt>
40053e: b8 00 00 00 00 mov $0x0,%eax
400543: 5d pop %rbp
400544: c3 retq
使用readelf
,我们可以发现每个x
在最终的可执行文件中都有自己的符号:
$ readelf -s a.out
...
45: 0000000000600910 4 OBJECT LOCAL DEFAULT 25 x.2163
46: 0000000000600914 4 OBJECT LOCAL DEFAULT 25 x.2162
这是C代码:
int main()
{
static int x = 8;
{
static int x = 9;
printf("%d",x);
}
printf("%d",x);
return 0;
}
答案 1 :(得分:2)
在内部,编译器重命名具有不同范围的同义变量。 考虑一下你的文件:
// file pradipta.c
#include <stdio.h>
int main () {
static int x = 8;
{
static int x = 9;
}
printf ("%d\n", x);
}
然后用
编译它(在Linux上使用GCC) gcc -fdump-tree-all -O -Wall pradipta.c -o pradipta.bin
然后你会得到很多pradipta.c.[0-9]*t.*
个文件。它们向您显示GCC表示的部分(因此不完整)转储。某些内部变量可能不同但名称相同。在编译器内部,变量在内部由一些复杂的数据结构表示(GCC用语中的tree
节点,在gimple
指令中使用),你可以有两个不同的这种结构,具有相同的“可打印”名称
您还可以使用MELT来探索GCC内部(或通过扩展带有MELT扩展的GCC来自定义其行为)。
另请阅读λ-calculus中的α转换。
在实践中,避免使用不同嵌套范围的同义变量。它们使您的代码对人类来说非常难以理解(即使编译器为您的代码提供了非常精确和明确的含义)。 -Wall
选项会询问所有警告,并且您会收到有关此类情况的警告。
答案 2 :(得分:1)
在函数调用期间,静态值将保持不变。
但在同一功能范围内单独关注。将printf放在你会理解的支架内
int main()
{
static int x = 8;
{
static int x = 9;
**printf("%d",x);**
}
printf("%d",x);
}
答案 3 :(得分:1)
静态变量只创建一次,并在内存中保留变量的范围。
使用时
{
static int x = 9;
printf("%d",x) // would print 9 only
}
这会创建一个新范围,x
与在大括号外定义的x
不同。
范围
如果在全局空间中声明了静态变量,那么它在整个文件中都是持久的。
但是还要记住局部范围变量优先于具有相同名称的全局变量。
答案 4 :(得分:1)
想象一下,每个开口都会创建一个范围{并且每次关闭都会关闭}。并且,对于每个新范围,变量的名称都以范围的名称(可以与函数的名称同化,或者对于匿名构造,如示例中的匿名构造,具有通用名称)加上前缀(精神上) “scope1”,“scope2”,“scope3”序列。
所以,基本上,你定义了两个变量,而不是一个:
static int main.x = 8;
和
static int main.scope1.x = 9;
这两个都是静态的,但它们(对于编译器和程序的逻辑)有不同的名称,并且表现得像不同的变量。只有他们缩短的名字是相同的,“x”,这是让你困惑的,但变量实际上是不同的。他们尊重你对“静态”的看法,但没有冲突。
一句警告:在“scope1”中,变量“main.scope1.x”隐藏变量“main.x”。
请记住,使用范围名称进行“重命名”仅仅是一个类比,而不是真实的。不过,我希望它有助于理解这个问题。
答案 5 :(得分:1)
理论编译器可以保留遇到符号的堆栈。解析'{'时,编译器可以将此分隔符放入堆栈中,当遇到'}'符号时,它将删除最后一个'{'...'}'区域之间的所有符号。
当编译器解析某个符号时,它可以直接深入到符号堆栈以找到匹配或宣布错误。
在解析此文件的每个关键点,此编译器将具有以下符号堆栈:
main main main main main main main
{ { { { {
x x x x
{ {
x
这种方法实际上非常接近于c-compilers的遗留实现 - x-es也将被放置到现实中。