关于在 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."
至于是否正确...如果正确,那么我有点困惑为什么上述代码块:
- 被归类为未定义行为
- 可能导致程序崩溃
- 可以有一些其他效果
评论以上案例:
我对未定义行为的理解是,在运行时间,任何事情都可能发生。话虽如此,在我看来,在上面的代码中,只有非常定义的 子集 的事情才会发生。我知道 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)
我是这个论坛的新手,所以如果有任何过分的格式选择,请告诉我,我会及时更新。
在C Programming: A Modern Approach一书中(K.N.King着),写了下面这段话:
If a pointer variable
p
hasn't been initialized, attempting to use the value ofp
in any way causes undefined behavior. In the following example, the call ofprintf
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."
至于是否正确...如果正确,那么我有点困惑为什么上述代码块:
- 被归类为未定义行为
- 可能导致程序崩溃
- 可以有一些其他效果
评论以上案例:
我对未定义行为的理解是,在运行时间,任何事情都可能发生。话虽如此,在我看来,在上面的代码中,只有非常定义的 子集 的事情才会发生。我知道 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)