【问题标题】:why wild pointer holds zero address rather than garabge address?为什么野指针持有零地址而不是垃圾地址?
【发布时间】:2020-08-29 04:24:48
【问题描述】:

我一直试图在不使用 sizeof() 的情况下查找特定数据类型(如“int”)的大小,结果发现:

#include<stdio.h>

int main() {

    int *ptr;   /*Declare a pointer*/
    printf("Size of ptr = %d\n",ptr);
    ptr++;

    printf("Size of ptr = %d\n",ptr);
    return 0;
}

这将返回正确的 int 大小。如何? 野指针不应该包含垃圾地址而不是零。如果它包含零,它与 NULL 指针有何不同,因为 NULL 是 (void*)0 ?

【问题讨论】:

  • 这是未定义的行为,任何事情都可能发生。你不应该有任何特别的期望
  • ptr 未初始化并且具有不确定的值。阅读它是未定义的行为。你不会从这段代码中学到任何有用的东西。
  • 垃圾与零有何不同?这基本上是你的问题。实际上,C++ 标准并没有说“野指针”具有“垃圾值”。它说读取未初始化变量的程序具有未定义的行为。这意味着编译器可以以他们喜欢的任何方式编译此类程序,并且仍然符合 C++ 标准。
  • @M.M 当我读到这个问题时,OP 试图通过在增量之后减去指针值来确定sizeof int。我相信这在技术上是 UB,但是在大多数实现中它仍然可以按预期工作。在它成为语言的一部分之前,它与 offsetof 的旧宏并没有什么不同。
  • @kpk 您的未分配指针的初始值为0(与NULL 相同)纯属偶然。下次运行时,或者使用下一版本的编译器编译时,该值可能会有所不同。也就是说,(int)((int*)ptr + 1) - (int)((int*)ptr) == sizeof int 成立,无论ptr 的值如何,在大多数实现中,指针“适合”到 int 中,并且它的 UB 部分具有更微妙的变化。

标签: c++ c pointers


【解决方案1】:

由于ptr 未初始化,它的值是不确定的,访问它的值会产生未定义的行为。有点讽刺的是,“未定义”的含义是由 C 和 C++ 标准定义的,意思是“这个标准不限制发生的事情”。

初学者经常错误地认为这意味着它必须包含“垃圾值”或者是“野指针”或“在此处添加一些丰富多彩的描述”,但事实并非如此。

“值不确定”或“访问该值的行为未定义”的含义是允许访问该值的代码的任何行为。

访问该值是打印它、递增它或(在指针的情况下)取消引用它(访问由指针的值标识的地址的内容)所必需的。

访问该值的代码行为未定义。给出零打印值、42 或“垃圾值”都是正确的结果。然而,同样地,结果可能意味着没有输出或不希望的操作,例如重新格式化硬盘驱动器。如果重复执行代码,行为甚至可能会随着时间而改变。或者它可能是 100% 可重复的(对于特定的编译器、特定的操作系统、特定的硬件等)。

实际上,具有未定义行为的代码在程序测试期间没有出现故障迹象是很常见的,但后来在客户的计算机上安装和执行程序时会导致一些令人讨厌的、可见但意想不到的效果。这往往会导致脾气暴躁的客户、开发人员可能无法复制的错误报告以及开发人员在尝试修复该漏洞时的压力。

因此试图解释为什么未定义的行为会导致某些特定结果(例如打印零值)是没有意义的。

【讨论】:

  • 关于“值是不确定的”的意思……是允许访问该值的代码的任何行为”:这在 C 中是不正确的。在 C 中,使用不确定的值(不是“访问”;访问包括写入,当然可以写入具有不确定值的对象)产生一些值,并且该值在每个实例中可能不同(例如,printf("%d %d", x, x) 可能产生“3 7”)。 (如果类型有陷阱表示,则值可能是陷阱表示,这会导致未定义的行为,但这是一个单独的问题。)
  • 关于“试图解释为什么未定义的行为会导致某些特定结果(例如打印零值)因此毫无意义”:这是不正确的。 C 标准没有对它所说的“未定义”行为强加任何要求这一事实并不意味着没有其他要求或因果关系。错误程序的行为通常包含错误的线索,即使这些行为不是由 C 标准定义的,通过推理行为找到错误通常比在没有指导的情况下搜索源代码更便宜、更快。
  • 另外,一些语言标准没有定义的行为被编译器定义为扩展,当然可以解释。
  • @EricPostpischil - 随意发布您认为正确解决您观点的问题的答案。
【解决方案2】:

第一次打印将有垃圾或零,这取决于您的编译器和内存位置中的先前值。 如果它为零,那么第二次打印的大小将是 int,因为递增指针会随着指针的大小而增加。

例如:

char *x = 0;
x++; //x=1

int *y = 0;
y++; //y=4

在您的情况下,如果您在第一次打印时得到 0,则与将其初始化为 NULL 相同,但 您不能将其视为始终为零。。 p>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多