gpt4 book ai didi

c - 静态修饰符在 C 中如何工作?

转载 作者:行者123 更新时间:2023-12-01 22:58:04 24 4
gpt4 key购买 nike

我试图理解 "static" 修饰符在 C 中是如何工作的,我一直在寻找它的含义,但我发现的一切似乎都有些模糊。

It is a modifier to allow the values of a variable to exist until the end of the program execution.

我理解它的含义和目的,但除了这个定义之外,我想了解它在底层是如何工作的,所以我生成了 C 代码的汇编

char    *thing(char *a)
{
char *b;

b = malloc(3);

b[0] = 'y';
b[1] = '\0';
return (b);
}

char *some(int fd)
{
static char *a = "happened";
a = thing(a);
return (a);
}

我用非静态 a 变量创建了另一个代码并得到了这个

/* With static variable */
.file "static_test.c"
.text
.globl thing
.type thing, @function
thing:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movq %rdi, -24(%rbp)
movl $3, %edi
call malloc@PLT
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movb $121, (%rax)
movq -8(%rbp), %rax
addq $1, %rax
movb $0, (%rax)
movq -8(%rbp), %rax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size thing, .-thing
.globl some
.type some, @function
some:
.LFB7:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq a.0(%rip), %rax
movq %rax, %rdi
call thing
movq %rax, a.0(%rip)
movq a.0(%rip), %rax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE7:
.size some, .-some
.section .rodata
.LC0:
.string "happened"
.section .data.rel.local,"aw"
.align 8
.type a.0, @object
.size a.0, 8
a.0:
.quad .LC0
.ident "GCC: (GNU) 12.1.0"
.section .note.GNU-stack,"",@progbits

/* no static variable */
.file "nostatic_test.c"
.text
.globl thing
.type thing, @function
thing:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movq %rdi, -24(%rbp)
movl $3, %edi
call malloc@PLT
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movb $121, (%rax)
movq -8(%rbp), %rax
addq $1, %rax
movb $0, (%rax)
movq -8(%rbp), %rax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size thing, .-thing
.section .rodata
.LC0:
.string "happened"
.text
.globl some
.type some, @function
some:
.LFB7:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
leaq .LC0(%rip), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call thing
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE7:
.size some, .-some
.ident "GCC: (GNU) 12.1.0"
.section .note.GNU-stack,"",@progbits

问题是,发生了什么,两个汇编代码之间的区别,以及它在编译时和程序执行时的行为如何。

最佳答案

在静态版本中,您在 .data 部分中保留了一个指针大小的数据,它由程序文件/图像初始化以引用字符串文字(在 .rodata 部分)。这是

a.0:
.quad .LC0

在非静态版本中,变量是“自动的”——函数的局部变量,在函数进入时创建,并在函数退出时有效销毁。因为变量在每次调用函数时都存在,所以每次都必须对其进行初始化。在您显示的(未优化的)代码中,这个自动变量存在于堆栈中。 (优化会改进代码。)

静态变量在这种初始化方面可以享受高效,而局部变量则可以享受驻留在 CPU 寄存器中的性能可能性(快速访问且不占用内存),并且与静态变量相比可能具有递归和线程安全性。

正如您所注意到的,静态变量在函数停止后仍然存在,因为它具有全局存储并且编译器知道如何访问它。相比之下,自动/基于堆栈的变量在从函数返回后丢失——更具体地说,每次调用函数时都会重新创建变量,因此旧副本不再(实际上)可访问。您可以创建一个指向自动变量的指针,但在函数退出后使用/取消引用该指针将是一个逻辑错误。

关于c - 静态修饰符在 C 中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72538570/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com