C 在两个函数中声明变量,但仅初始化其中一个

C 在两个函数中声明变量,但仅初始化其中一个,c,scope,C,Scope,变量a在两个单独的函数中声明,但仅在其中一个函数中初始化。main函数调用声明和初始化变量的函数,然后调用第二个函数,该函数在不初始化变量的情况下重新声明该变量。它打印42,即使a在不同的函数范围内初始化,其数据在函数完成后应该被销毁。为什么会这样 #include <stdio.h> void foo() { int a = 42; } void bar() { int a; printf("%d",a); } main() { foo();

变量a在两个单独的函数中声明,但仅在其中一个函数中初始化。main函数调用声明和初始化变量的函数,然后调用第二个函数,该函数在不初始化变量的情况下重新声明该变量。它打印42,即使a在不同的函数范围内初始化,其数据在函数完成后应该被销毁。为什么会这样

#include <stdio.h>
void foo() {
    int a = 42;
}
void bar() {
    int a;
    printf("%d",a);
}
main() {
    foo();
    bar();
}
#包括
void foo(){
INTA=42;
}
空条(){
INTA;
printf(“%d”,a);
}
main(){
foo();
bar();
}

ooooo,这是个好主意。官方还没有定义。但我敢打赌,它们中的很多都会打印42,因为a可能会在堆栈上使用相同的内存地址

因此,当函数被调用时,程序应该返回的PC(程序计数器)的值与参数一起被推送到堆栈上,这就是该函数工作原理的基础。在这种情况下,foo和bar都没有参数,因此只有一个指针会被推送到堆栈上(比如说,从相对地址0开始总共有4个字节)

然后,当函数启动时,其变量被推送到堆栈上。在这种情况下,它们都有一个将被推送的In,每个In也是4个字节(总共8个字节,从相对地址4开始)


这是C/C++中从其他函数/程序中获取数据的常用方法,否则该函数不允许访问这些函数/程序

官方的答案是

void bar() {
    int a;
    printf("%d",a);
}
调用“未定义的行为”。任何事情都有可能发生。它可以打印一首诗,格式化你的硬盘,打开白宫圣诞树上的灯,。。。它甚至可能会打印42,有些人会告诉你在某些情况下会发生什么


在其他地方有另一个名为
a
的变量这一事实与未定义的行为无关。您正在打印未初始化的变量<
foo
中的code>a与bar中的
a
在概念上是不同的变量

虽然UB(根据标准)可以做@pm100建议的任何奇怪的事情,但在现实世界中,它会打印出某个随机内存位置或寄存器中的任何内容。所以,一个未定义的值

它会打印42吗?可能地a:因为有一个随机的机会,未定义的值是42,b:因为可能内存/寄存器是由
foo
用42写入的,并且没有被其他内容覆盖

我能依靠它吗?100%,不

未定义的行为

如果优化关闭,则观察到的行为同时为clang和gcc print 42。如果添加-O1,foo函数实际上会消失,printf会打印一些垃圾

下面的程序向您显示a所指向的有效地址在两个函数中是相同的

#include <stdio.h>
#include <stdint.h>
void foo();
void bar();

void foo() {
  uint8_t a = 255;
  uint8_t b = 255;
  printf("%p\n",&a);
}

void bar() {
  uint16_t a;
  printf("%p\n",&a);
  printf("%hu\n",a);
}
int main(void) {
  foo();
  bar();
}

这是我的机器上观察到的今天在这种天气条件下的行为。当然,你可以观察飞猪、粉红大象或任何形式的动物,同时尝试观察上述代码的实际功能。

它们是不同的
a
s。了解变量作用域。你告诉我们,它是否打印42?顺便说一句,它实际上在两个函数中定义,但只在一个函数中初始化。问题中的措辞倒过来了谢谢@tinythebrotonosaurusah,该死。我以为这是复制品。事实并非如此,我想说的是
c++
,但我认为这里有很多相同的原则。Eric Lippert通常有很好的答案:我打赌甚至更多的人会完全从
foo
中优化
a
0x7fff54dd259e
0x7fff54dd259e
65535