2010-10-06 65 views
2

因此,可以说我有这样的代码当你在C中引用静态变量时究竟发生了什么?

int my_static_int = 4; 
func(&my_static_int); 

我传递的函数指针my_static_int,效果显着。但是,编译代码时会发生什么?大道,我认为:

1)当你宣布一个非指针变量,C自动创建的指针,并做一些事情像内部的typedef my_static_int为*(internal_reference

无论如何,我希望我的问题是足够描述的

回答

2

如果您确实想知道代码在外观下的外观,您必须让编译器生成汇编代码(gcc可以使用-S选项执行此操作)。

当你真正把C和指针指向最深层时,你会意识到它只是被传入的变量的地址而不是变量的值。由于指针直接从代码移到堆栈(地址可能在链接时间或加载时间,而不是运行时间),所以不需要创建额外的内存来存放指针。

由于编译后的代码已经知道类型以及如何操作,因此也不需要创建内部类型。

记住,这是实现特定的,考虑下面的代码:

int my_static_int = 4; 
static void func (int *x) { 
    *x = *x + 7; 
} 
int main (void) { 
    func(&my_static_int); 
    return 0; 
} 

,当与gcc -S编译得到汇编,生产:

 .file "qq.c" 
.globl _my_static_int 
     .data 
     .align 4 
_my_static_int: 
     .long 4 
     .text 
     .def _func; .scl 3;  .type 32;  .endef 
_func: 
     pushl %ebp 
     movl %esp, %ebp 
     movl 8(%ebp), %eax 
     movl 8(%ebp), %edx 
     movl (%edx), %edx 
     addl $7, %edx 
     movl %edx, (%eax) 
     popl %ebp 
     ret 
     .def ___main;  .scl 2;  .type 32;  .endef 
.globl _main 
     .def _main; .scl 2;  .type 32;  .endef 
_main: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $8, %esp 
     andl $-16, %esp 
     movl $0, %eax 
     addl $15, %eax 
     addl $15, %eax 
     shrl $4, %eax 
     sall $4, %eax 
     movl %eax, -4(%ebp) 
     movl -4(%ebp), %eax 
     call __alloca 
     call ___main 
     movl $_my_static_int, (%esp) 
     call _func 
     movl $0, %eax 
     leave 
     ret 

最重要的一点是这些部分:

movl $_my_static_int, (%esp) ; load address of variable onto stack. 
call _func     ; call the function. 
: 
movl 8(%ebp), %eax ; get passed parameter (the address of the var) into eax 
movl 8(%ebp), %edx ; and also into edx. 
movl (%edx), %edx ; get the value from the address (dereference). 
addl $7, %edx  ; add 7 to it. 
movl %edx, (%eax) ; and put it back into the same address. 

因此地址已通过,并用于获取变量。

4

指针只是一个术语,可以帮助我们理解正在发生的事情。

&运算符与变量一起使用时,仅表示地址。在运行时不会创建“指针”,只是将变量的地址传递给函数。

如果您有:

int x = 3; 
int* p = &x; 

则将P持有一个内存地址的变量。该内存地址是一个int。

0

为什么不看组装输出?您可以使用-S选项或gcc或(如果您的系统使用GNU工具链)在生成的目标文件或可执行文件上使用objdump -d命令执行此操作。

1

编译代码时,函数func接收到您的my_static_int变量的地址作为参数。没有其他的。

当您声明非指针变量时,不需要创建任何隐式指针。从你的问题中你不清楚你是如何来到这个奇怪的想法。

0

简单的回答是,目标代码会生成一个对符号的引用,其中my_static_int被分配(通常位于目标模块的静态数据段中)。

因此,变量的地址在加载时(当它被分配一个真实的物理地址时)被解析,并且加载程序修正对变量的引用,并用它的地址填充它。

相关问题