因此,可以说我有这样的代码当你在C中引用静态变量时究竟发生了什么?
int my_static_int = 4;
func(&my_static_int);
我传递的函数指针my_static_int,效果显着。但是,编译代码时会发生什么?大道,我认为:
1)当你宣布一个非指针变量,C自动创建的指针,并做一些事情像内部的typedef my_static_int为*(internal_reference)
无论如何,我希望我的问题是足够描述的
因此,可以说我有这样的代码当你在C中引用静态变量时究竟发生了什么?
int my_static_int = 4;
func(&my_static_int);
我传递的函数指针my_static_int,效果显着。但是,编译代码时会发生什么?大道,我认为:
1)当你宣布一个非指针变量,C自动创建的指针,并做一些事情像内部的typedef my_static_int为*(internal_reference)
无论如何,我希望我的问题是足够描述的
如果您确实想知道代码在外观下的外观,您必须让编译器生成汇编代码(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.
因此地址已通过,并用于获取变量。
指针只是一个术语,可以帮助我们理解正在发生的事情。
&运算符与变量一起使用时,仅表示地址。在运行时不会创建“指针”,只是将变量的地址传递给函数。
如果您有:
int x = 3;
int* p = &x;
则将P持有一个内存地址的变量。该内存地址是一个int。
为什么不看组装输出?您可以使用-S
选项或gcc
或(如果您的系统使用GNU工具链)在生成的目标文件或可执行文件上使用objdump -d
命令执行此操作。
编译代码时,函数func
接收到您的my_static_int
变量的地址作为参数。没有其他的。
当您声明非指针变量时,不需要创建任何隐式指针。从你的问题中你不清楚你是如何来到这个奇怪的想法。
简单的回答是,目标代码会生成一个对符号的引用,其中my_static_int
被分配(通常位于目标模块的静态数据段中)。
因此,变量的地址在加载时(当它被分配一个真实的物理地址时)被解析,并且加载程序修正对变量的引用,并用它的地址填充它。