简体   繁体   English

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

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

So lets say I have this code 所以说我有这个代码

int my_static_int = 4;
func(&my_static_int);

I passed the function a pointer to my_static_int, obviously. 显然,我向函数传递了指向my_static_int的指针。 But what happens when the code is compiled? 但是,编译代码时会发生什么? Avenue I've considered: 我考虑过的大道:

1) When you declare a non-pointer variable, C automatically creates its pointer and does something internally like typedefs my_static_int to be *( internal_reference ) 1)当您声明一个非指针变量时,C会自动创建其指针,并在内部做一些类似typedefs my_static_int的*( internal_reference

Anyway, I hope that my question is descriptive enough 无论如何,我希望我的问题足够描述性

Pointers are just a term to help us humans understand what's going on. 指针只是一个术语,可以帮助我们人类了解正在发生的事情。

The & operator when used with a variable simply means address of. &运算符与变量一起使用时,仅表示地址。 No "pointer" is created at runtime, you are simply passing in the address of the variable into the function. 在运行时没有创建“指针”,您只是将变量的地址传递给函数。

If you have: 如果你有:

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

Then p is a variable which holds a memory address. 那么p是一个保存内存地址的变量。 Inside that memory address is an int. 在该内存地址内是一个int。

If you really want to know how the code looks under the covers, you have to get the compiler to generate the assembler code ( gcc can do this with the -S option). 如果您真的想知道代码的幕后外观,则必须让编译器生成汇编代码( gcc可以使用-S选项执行此操作)。

When you truly grok C and pointers at their deepest level, you'll realise that it's just the address of the variable being passed in rather than the value of the variable. 当真正了解C和指针的最深层次时,您会意识到,它只是传入的变量的地址,而不是变量的值。 There's no need for creating extra memory to hold a pointer since the pointer is moved directly from the code to the stack (the address will probably have been set either at link time or load time, not run time). 无需创建额外的内存来容纳指针,因为指针直接从代码移到了堆栈(地址可能是在链接时或加载时设置的,而不是在运行时设置的)。

There's also no need for internal type creation since the compiled code already knows the type and how to manipulate it. 因为编译后的代码已经知道类型以及如何操作它,所以也不需要内部类型创建。

Keeping in mind that this is implementation-specific, consider the following code: 请记住,这是特定于实现的,请考虑以下代码:

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

which, when compiled with gcc -S to get the assembler, produces: 使用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

The important bit is these sections: 重要的是这些部分:

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.

Hence the address is passed, and used to get at the variable. 因此, 地址被传递,并用于获取变量。

When the code is compiled, function func receives the address of your my_static_int variable as parameter. 编译代码后,函数func接收my_static_int变量的地址作为参数。 Nothing else. 没有其他的。

There no need to create any implicit pointers when you declare a non-pointer variable. 声明非指针变量时,无需创建任何隐式指针。 It is not clear from your question how you came to this weird idea. 从您的问题尚不清楚您是如何想到这个奇怪的想法的。

Why not look at the assembly output? 为什么不看汇编输出? You can do this with gcc using the -S option, or (if your system uses the GNU toolchain) using the objdump -d command on the resulting object file or executable file. 您可以使用-S选项使用gcc进行此操作,也可以对所得的目标文件或可执行文件使用objdump -d命令(如果您的系统使用GNU工具链)。

The simple answer is that the object code generates a reference to the symbol where my_static_int is allocated (which is typically in the static data segment of your object module). 简单的答案是,目标代码生成对分配了my_static_int的符号的引用(通常位于目标模块的静态数据段中)。

So the address of the variable is resolved at load time (when it is assigned a real physical address), and the loader fixes up the reference to the variable, filling it in with its address. 因此,变量的地址在加载时解析(当为其分配了实际的物理地址时),并且加载程序将对变量的引用固定,并用其地址填充。

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

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