当您在 C 中取消引用静态变量时到底会发生什么?

发布于 2024-09-26 10:03:16 字数 299 浏览 2 评论 0原文

假设我有这段代码,

int my_static_int = 4;
func(&my_static_int);

显然我向函数传递了一个指向 my_static_int 的指针。但是当代码被编译时会发生什么呢?我考虑过的途径:

1)当你声明一个非指针变量时,C会自动创建它的指针并在内部执行一些操作,例如 typedefs my_static_int to be *(internal_reference)

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

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. 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)

Anyway, I hope that my question is descriptive enough

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

寂寞花火° 2024-10-03 10:03:17

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

的&与变量一起使用时,运算符仅表示地址。运行时不会创建“指针”,您只需将变量的地址传递到函数中即可。

如果有:

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

那么 p 是一个保存内存地址的变量。该内存地址里面是一个 int 。

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. Inside that memory address is an int.

甜心小果奶 2024-10-03 10:03:17

如果您确实想知道代码在幕后的样子,您必须让编译器生成汇编代码(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.

因此是地址 被传递,并用于获取变量。

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).

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. 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:

        .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.

清浅ˋ旧时光 2024-10-03 10:03:17

编译代码时,函数 func 接收 my_static_int 变量的地址作为参数。没有别的了。

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

When the code is compiled, function func receives the address of your my_static_int variable as parameter. 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.

情绪操控生活 2024-10-03 10:03:17

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

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.

弥繁 2024-10-03 10:03:17

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

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

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).

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文