这是我提出这个问题的原因:
static ProfileUnit* g_units_header;
static ProfileUnit* g_units_tail;
static int g_units_count;
void Destroy() {
if (!g_units_header) {
return;
}
typedef std::vector<ProfileUnit*> PUVect;
PUVect stack(g_units_count);
ProfileUnit* p = g_units_header;
while (p) {
stack.push_back(p);
p = p->next;
}
for (PUVect::const_iterator it = stack.begin(); it != stack.end(); ++it) {
free(*it);
}
g_units_header = g_units_tail = nullptr;
g_units_count = 0;
}
如果“ g_units_header”为nullptr,“堆栈”和“ p”是否会出现在调用堆栈中?这不是一个很好的例子,我只想解释这种情况。只需关注问题即可。
答案 0 :(得分:2)
(为便于说明,我将在问题的原始版本中使用稍微改动的代码。您已经编辑了问题以更改代码,但这并没有改变答案。)
实际上,答案取决于所使用的编译器和优化选项。一些可能的结果:
val
完全优化,而与p
的值无关。val
放在寄存器中(这算作“内存”吗?)val
放置在堆栈上,而与p
的值无关。val
仅在p
不是NULL
时才放在堆栈上。在我的计算机上,gcc -O3
执行#4:
$ cat test.c
#include <stdio.h>
void foo(int* p) {
if (!p) return;
int val = 0xdeadbeef;
scanf("%d", &val);
}
已编译:
$ gcc -S -O3 test.c
输出(为简洁起见进行编辑):
$ cat test.s
_foo: ## @foo
testq %rdi, %rdi ## <<< p == NULL?
je LBB0_2 ## <<< Will jump over the stack allocation below
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp ## <<< Allocate stack for val
movl $-559038737, -4(%rbp) ## 0xdeadbeef
leaq L_.str(%rip), %rdi
leaq -4(%rbp), %rsi
xorl %eax, %eax
callq _scanf
addq $16, %rsp ## <<< Deallocate val
popq %rbp
LBB0_2:
retq
答案 1 :(得分:0)
尽管编译器有很多回旋余地,尤其是对于经证明不会产生任何可观察到的效果的代码,但C标准确实指定了自动变量(局部变量)的生存期始于该块的输入。声明的内容(这是您要查询的情况下foo
的正文。)[注1]
在执行foo
之前达到声明为止(如果已达到声明),该变量具有不确定的值,这限制了它的使用。同样,变量的名称在声明之前不可见。但是,变量确实存在(除非已被消除,因为编译器已确定它不相关)。
总的来说,这不值得担心。 “分配”一个自动变量通常包括递减函数入口上的堆栈指针。通过对所有函数的自动变量的大小求和,只需完成一次。电脑不仅仅指望手指,还可以指望电脑。它们可以在与从堆栈指针中减去一个大数相同的时间内减去一个大数。您唯一可能会注意到这种效果的情况是您的函数具有兆字节的局部变量。您应该避免这样做。