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