关于在 printf 函数中使用未初始化的整数指针的行为的问题

Question about the behavior of uninitialized pointers to integers when used in the printf function

我是这个论坛的新手,所以如果有任何过分的格式选择,请告诉我,我会及时更新。

C Programming: A Modern Approach一书中(K.N.King着),写了下面这段话:

If a pointer variable p hasn't been initialized, attempting to use the value of p in any way causes undefined behavior. In the following example, the call of printf may print garbage, cause the program to crash, or have some other effect:

int *p;
printf("%d", *p);

据我了解指针以及编译器如何处理它们,声明 int *p 有效地说,"Hey, if you dereference p in the future, I will look at a block of four consecutive bytes in memory, whose starting address is the value contained in p, and interpret those 4 bytes as a signed integer."

至于是否正确...如果正确,那么我有点困惑为什么上述代码块:

  1. 被归类为未定义行为
  2. 可能导致程序崩溃
  3. 可以有一些其他效果

评论以上案例:

我对未定义行为的理解是,在运行时间,任何事情都可能发生。话虽如此,在我看来,在上面的代码中,只有非常定义的 子集 的事情才会发生。我知道 p (由于缺乏初始化)正在存储一个随机地址,该地址可以指向内存中的任何位置。但是,当 printf 被传递了取消引用的值 *p 时,编译器不会只查看 4 个连续的内存字节(从任意随机地址开始)并将这 4 个字节解释为有符号整数?

因此,printf 应该只做一件事:打印一个介于 -2,147,483,648 到 2,147,483,647 之间的数字。显然,这是很多 不同的 可能的输出,但这真的符合 "undefined behavior" 的条件吗?此外,这样的 "undefined behavior" 怎么会导致 "program crash" 或 "have some other effect".

任何澄清将不胜感激!谢谢!

未定义行为定义为"we are not specifying what must happen, it's up to the implementers."

在实际意义上,*p 可能包含该内存区域最后保存的任何内容,可能是零,可能是更随机的东西,可能是以前使用的一大块数据。有时,为了安全起见,编译器会将内存隐式归零,从而牺牲一些时间来提供该功能。

值得注意的是,如果 p 被定义为 char*,并且您对它进行了 printf,它会尝试打印内容,直到找到 0x00。如果这将您带到内存边界,您可能会遇到分段错误。

未初始化值的值为不确定。它可以包含任何值(包括 0),甚至有可能在您每次尝试读取它时读取到不同的值。该值也可能是 陷阱表示 ,这意味着尝试读取它会触发处理器异常,从而导致程序崩溃。

假设您很幸运并且能够读取 p 的值,由于大多数系统使用的虚拟内存模型,该值可能不对应于映射到进程内存的地址 space.因此,如果您尝试通过取消引用指针来读取该地址,则会触发可能导致程序崩溃的分段错误。

请注意,在这两种情况下,崩溃都发生在 printf 被调用之前。

此外,允许编译器假设您的程序没有未定义的行为,并将根据该假设执行优化。这会使您的程序以您可能意想不到的方式运行。

至于为什么做这些事情是未定义的行为,因为C standard是这么说的。特别是,附录 J2 给出了未定义行为的示例:

The value of an object with automatic storage duration is used while it is indeterminate. (6.2.4, 6.7.9, 6.8)