Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 嵌套范围如何影响堆栈深度?_C_Assembly_Compiler Construction_Compiler Optimization - Fatal编程技术网

C 嵌套范围如何影响堆栈深度?

C 嵌套范围如何影响堆栈深度?,c,assembly,compiler-construction,compiler-optimization,C,Assembly,Compiler Construction,Compiler Optimization,我尝试使用MSVC将下面的c代码编译成程序集,有(CL TestFile.c/Fa/Ot)和没有优化(CL TestFile.c/Fa),结果是它们产生相同的堆栈深度 为什么编译器在知道最多使用16个字节时,对3个变量x、y和z中的每一个都使用8个字节?它不能使用y$1=4和z$2=8而不是y$1=4和z$2=4,因此y和z在堆栈上使用相同的内存而不会出现任何问题吗 intmain(){ int x=123; 如果(x==123){ int y=321; } 否则{ int z=234; } }

我尝试使用MSVC将下面的c代码编译成程序集,有(CL TestFile.c/Fa/Ot)和没有优化(CL TestFile.c/Fa),结果是它们产生相同的堆栈深度

为什么编译器在知道最多使用16个字节时,对3个变量x、y和z中的每一个都使用8个字节?它不能使用
y$1=4
z$2=8
而不是
y$1=4
z$2=4
,因此
y
z
在堆栈上使用相同的内存而不会出现任何问题吗

intmain(){
int x=123;
如果(x==123){
int y=321;
}
否则{
int z=234;
}
}

嵌套范围不影响堆栈深度。根据C标准,嵌套的作用域会影响标识符的可见性,并且不会对C实现如何使用堆栈(如果有)提出任何要求。C标准允许C编译器生成获得相同可观察行为的任何代码

对于问题中显示的程序,唯一可观察到的行为是以成功状态退出,因此一个好的编译器在优化时应该生成一个最小的程序。例如:

Clang11.0.1也是如此。如果MSVC没有,那就是它的缺陷。(但是,可能是开关
/Os
/Ot
不要求优化或不要求太多优化;当与其他优化开关一起使用时,它们可能只是表示对速度或时间的偏好。)


此外,一个好的编译器应该对对象的使用进行生命周期分析,构造一个图来表示节点在代码中的位置,并用值的创建或使用来标记,有向边是潜在的程序控制流(或源代码的一些等价表示)。然后,应该生成汇编程序(或中间代码)来实现图所需的语义。如果两组源代码具有等效的图,则编译器应为它们生成等效的程序集(或中间代码)(达到处理复杂图的合理能力),而不管是否使用嵌套范围中的定义。

我现在尝试使用:CL TestFile.c/Fa/Ot编译,以便进行优化,但结果是一样的。编译器似乎没有对此进行优化。我希望这个程序能够编译成一条完全优化的返回指令,因为它什么也不做。@EugeneSh。不稳定,不应进行优化out@0___________我想挥发性可能还有其他的影响。。。因为这个问题与某些优化有关,所以为什么编译器在我的示例中不尝试减少堆栈深度?它不能减少大型函数的执行时间吗?@JasperNielsen:MSVC会进行此优化:。@PeterCordes:is
/Os
/Ot
是否不请求任何优化,而只是请求在需要优化的情况下,分别优先选择速度或时间?这就解释了为什么
/Os
/Ot
的代码不好,而
/O2
@JasperNielsen:事实上,即使在
if
的每个分支中添加
foo(&y)
foo(&z)
调用,也会使
x
不是编译时间常数,我们确实看到MSVC 19.14对
y
z
使用了相同的堆栈槽(注意
z$1=48
y$2=48
从RSP组装时间常数偏移量),这与此答案的最后一段所建议的好编译器完全一样。它似乎刚刚将它们组合成一个变量,该变量的值由一个分支决定。@EricPostDischil:IDK,
-Ot
使asm与无选项(调试模式)相同。但奇怪的是,对于Godbolt在WINE下的MSVC来说,asm并没有使RBP成为帧指针,所以它可能不是完全调试模式?如果OP想要使用标准的
-O2
-Ox
以外的选项,那么听起来他们需要查看MSVC手册。
; Parts of the assembly code
x$ = 0
y$1 = 4
z$2 = 8
main PROC
$LN5:
  sub rsp, 24
; And so on...
main:
        xor     eax, eax
        ret