繁体   English   中英

在C语言中取消引用静态变量时会发生什么情况?

[英]What exactly happens when you dereference a static variable in C?

所以说我有这个代码

int my_static_int = 4;
func(&my_static_int);

显然,我向函数传递了指向my_static_int的指针。 但是,编译代码时会发生什么? 我考虑过的大道:

1)当您声明一个非指针变量时,C会自动创建其指针,并在内部做一些类似typedefs my_static_int的*( 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变量的地址作为参数。 没有其他的。

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

为什么不看汇编输出? 您可以使用-S选项使用gcc进行此操作,也可以对所得的目标文件或可执行文件使用objdump -d命令(如果您的系统使用GNU工具链)。

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

因此,变量的地址在加载时解析(当为其分配了实际的物理地址时),并且加载程序将对变量的引用固定,并用其地址填充。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM