gpt4 book ai didi

c++ - 编译器会做什么

转载 作者:太空宇宙 更新时间:2023-11-04 05:02:06 24 4
gpt4 key购买 nike

我已经编程了几年,但令人尴尬的是,有一两件事我仍然不完全清楚。

下面的基本代码只是作为例子,当编译器遇到myFunc()时,str1和str2会存放到哪里呢?

它们是指向字符串文字的指针,所以我假设字符串文字将存储在只读内存中,但在这种情况下,一个指针是静态本地指针而另一个不是静态本地指针有什么区别?另外,我认为局部变量将存储在堆栈中,并且在调用函数之前不会分配它们?这令人困惑。

对于整数 var1,它是非静态的,但 var2 是静态的。编译器会不会在编译的时候把这个var2放到data段中。我读过另一篇文章 When do function-level static variables get allocated/initialized? ,局部静态变量将在第一次使用时创建和初始化,而不是在编译期间。那么在那种情况下,如果函数从未被调用怎么办?

提前感谢经验丰富的知识。

已编辑:从 main() 调用 myFunc()。这是一个打字错误,因为 myFunc() 甚至从未被调用过

int myFunc()
{
static char* str1 = "Hello";
char* str2 = "World";

int var1 = 1;
static int var2 = 8;

}

int main()
{

return myFunc();
}

最佳答案

编辑:

其他答案和评论是正确的 - 实际上,您的变量将被优化掉,因为它们甚至没有被使用。但让我们找点乐子,实际使用它们看看会发生什么。

我使用 gcc -S trial.c 按原样编译了 op 的程序,尽管从未调用过 myFunc,但此答案没有其他任何变化。

我稍微修改了您的程序以实际使用这些变量,这样我们就可以更多地了解编译器和链接器将做什么。在这里:

#include <stdio.h>

int myFunc()
{
static const char* str1 = "Hello";
const char* str2 = "World";

int var1 = 1;
static int var2 = 8;
printf("%s %s %d %d\n", str1, str2, var1, var2);
return 0;
}

int main()
{
return myFunc();
}

我用 gcc -S trial.c 编译并得到以下汇编文件:

    .file   "trial.c"
.section .rdata,"dr"
.LC0:
.ascii "World\0"
.LC1:
.ascii "%s %s %d %d\12\0"
.text
.globl myFunc
.def myFunc; .scl 2; .type 32; .endef
.seh_proc myFunc
myFunc:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $64, %rsp
.seh_stackalloc 64
.seh_endprologue
leaq .LC0(%rip), %rax
movq %rax, -8(%rbp)
movl $1, -12(%rbp)
movl var2.3086(%rip), %edx
movq str1.3083(%rip), %rax
movl -12(%rbp), %r8d
movq -8(%rbp), %rcx
movl %edx, 32(%rsp)
movl %r8d, %r9d
movq %rcx, %r8
movq %rax, %rdx
leaq .LC1(%rip), %rcx
call printf
movl $0, %eax
addq $64, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
call myFunc
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.data
.align 4
var2.3086:
.long 8
.section .rdata,"dr"
.LC2:
.ascii "Hello\0"
.data
.align 8
str1.3083:
.quad .LC2
.ident "GCC: (Rev1, Built by MSYS2 project) 5.4.0"
.def printf; .scl 2; .type 32; .endef

var1 甚至没有在程序集文件中找到。它实际上只是一个加载到堆栈上的常量。

在程序集文件的顶部,我们在 .rdata 部分中看到“World”(str2)。在汇编文件的下方,字符串“Hello”位于 .rdata 部分,但 str1 的标签(包含“Hello”的标签或地址)位于 .data 部分。 var2 也在 .data 部分。

这是 a stackoverflow question这更深入地研究了为什么会发生这种情况。

Another stackoverflow question指出 .rdata 部分是 .data 的只读部分,并解释了不同的部分。

希望这对您有所帮助。


编辑:

我决定尝试使用 -O3 编译器标志(高度优化)。这是我得到的程序集文件:

    .file   "trial.c"
.section .rdata,"dr"
.LC0:
.ascii "World\0"
.LC1:
.ascii "Hello\0"
.LC2:
.ascii "%s %s %d %d\12\0"
.section .text.unlikely,"x"
.LCOLDB3:
.text
.LHOTB3:
.p2align 4,,15
.globl myFunc
.def myFunc; .scl 2; .type 32; .endef
.seh_proc myFunc
myFunc:
subq $56, %rsp
.seh_stackalloc 56
.seh_endprologue
leaq .LC0(%rip), %r8
leaq .LC1(%rip), %rdx
leaq .LC2(%rip), %rcx
movl $8, 32(%rsp)
movl $1, %r9d
call printf
nop
addq $56, %rsp
ret
.seh_endproc
.section .text.unlikely,"x"
.LCOLDE3:
.text
.LHOTE3:
.def __main; .scl 2; .type 32; .endef
.section .text.unlikely,"x"
.LCOLDB4:
.section .text.startup,"x"
.LHOTB4:
.p2align 4,,15
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
subq $40, %rsp
.seh_stackalloc 40
.seh_endprologue
call __main
xorl %eax, %eax
addq $40, %rsp
ret
.seh_endproc
.section .text.unlikely,"x"
.LCOLDE4:
.section .text.startup,"x"
.LHOTE4:
.ident "GCC: (Rev1, Built by MSYS2 project) 5.4.0"
.def printf; .scl 2; .type 32; .endef

var1 现在只是一个放在寄存器 (r9d) 中的常量 1。 var2 也只是一个常量,但它放在堆栈上。此外,以更直接(高效)的方式访问字符串“Hello”和“World”。

所以,我决定尝试一些稍微不同的东西:

#include <stdio.h>

void myFunc()
{
static const char* str1 = "Hello";
const char* str2 = "World";

int var1 = 1;
static int var2 = 8;
printf("%s %s %d %d\n", str1, str2, var1, var2);

var1++;
var2++;
printf("%d %d", var1, var2);
}

int main()
{
myFunc();
myFunc();
return 0;
}

以及使用 gcc -O3 -S trial.c 的关联程序集

    .file   "trial.c"
.section .rdata,"dr"
.LC0:
.ascii "World\0"
.LC1:
.ascii "Hello\0"
.LC2:
.ascii "%s %s %d %d\12\0"
.LC3:
.ascii "%d %d\0"
.section .text.unlikely,"x"
.LCOLDB4:
.text
.LHOTB4:
.p2align 4,,15
.globl myFunc
.def myFunc; .scl 2; .type 32; .endef
.seh_proc myFunc
myFunc:
subq $56, %rsp
.seh_stackalloc 56
.seh_endprologue
movl var2.3086(%rip), %eax
leaq .LC0(%rip), %r8
leaq .LC1(%rip), %rdx
leaq .LC2(%rip), %rcx
movl $1, %r9d
movl %eax, 32(%rsp)
call printf
movl var2.3086(%rip), %eax
leaq .LC3(%rip), %rcx
movl $2, %edx
leal 1(%rax), %r8d
movl %r8d, var2.3086(%rip)
addq $56, %rsp
jmp printf
.seh_endproc
.section .text.unlikely,"x"
.LCOLDE4:
.text
.LHOTE4:
.def __main; .scl 2; .type 32; .endef
.section .text.unlikely,"x"
.LCOLDB5:
.section .text.startup,"x"
.LHOTB5:
.p2align 4,,15
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
subq $40, %rsp
.seh_stackalloc 40
.seh_endprologue
call __main
call myFunc
call myFunc
xorl %eax, %eax
addq $40, %rsp
ret
.seh_endproc
.section .text.unlikely,"x"
.LCOLDE5:
.section .text.startup,"x"
.LHOTE5:
.data
.align 4
var2.3086:
.long 8
.ident "GCC: (Rev1, Built by MSYS2 project) 5.4.0"
.def printf; .scl 2; .type 32; .endef

这看起来有点像原来的样子。 var1 仍然优化为常量,但 var2 现在再次位于 .data 部分。 “Hello”和“World”仍在 .rdata 部分中,因为它们是常量。

其中一条评论指出,在具有不同编译器的不同平台上,这会有所不同。我鼓励您尝试一下。

关于c++ - 编译器会做什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39515911/

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