地址0x0中的0xdeadbeef是什么意思?

时间:2014-11-09 07:44:35

标签: c linux

我刚刚在代码中看到以下行:

#define ERR_FATAL( str, a, b, c ) {while(1) {*(unsigned int *)0 = 0xdeadbeef;} }

我知道0xdeadbeef意味着错误,但是这个值在地址0中意味着什么呢? 地址0代表什么?

3 个答案:

答案 0 :(得分:11)

地址0x0被编译器识别为NULL pointer并且将成为implementation defined invalid memory address,在某些系统上确实是在系统内存中的第一个可寻址位置,但在其他系统上它只是代码中的占位符,用于某些通用无效内存地址。从C代码的角度来看,我们不知道将是什么地址,只是访问它是无效的。基本上,这段代码片段试图写入“非法”内存地址,值为0xdeadbeef。价值本身是一个十六进制,表示“死牛肉”,因此表明该程序是死牛肉(即一个问题),如果你不是一个英语母语人士我可以看到这可能不是那么清楚:)。我们的想法是,这将触发分段错误或类似错误,目的是通过立即终止程序而不通过清除或在此期间执行的其他操作(宏名称ERR_FATAL提示通知您存在问题。那)。大多数操作系统不允许程序直接访问系统中的所有内存,代码假定操作系统不允许您直接访问位于地址0x0的内存。鉴于您使用linux标记标记了此问题,这将是您将看到的行为(因为linux将不允许访问该内存地址)。请注意,如果您正在处理类似嵌入式系统的问题,那么这可能会导致一系列问题,因为您可能会覆盖重要的内容。

请注意,除了某些类型的未定义行为导致某些副作用之外,还有更好的方法来报告问题。使用像assert这样的东西可能是更好的选择。如果你想使用abort()终止程序是一个更好的选择,就像它在标准库中一样,并且完全符合你的要求。请参阅ComicSansMS的答案,了解更多关于为何这样做的原因。

答案 1 :(得分:7)

将此值(或该值的任何值)放在地址0中应该立即终止程序。

致命错误表示错误情况严重到程序无法安全地继续执行而不会有进一步数据损坏的风险。

特别是,不会执行待处理的清理操作,因为它们可能会产生不良影响。考虑将已损坏数据的缓冲区刷新到文件系统。相反,该程序将立即终止,并允许通过核心转储或附加调试器进一步检查该情况。

请注意,C已经为此提供了标准库函数:abort()。出于此目的,调用abort会更好,原因如下:

  • 写入地址0不保证终止程序。这不必要地限制了代码的可移植性,如果代码实际上被重新编译并在写入地址0的平台上执行导致实际的内存存储操作,则可能会产生破坏性后果。
  • 对于阅读代码的人来说,调用abort()更容易理解。您的问题证明许多开发人员无法理解有问题的代码应该做什么。虽然宏的名称和值deadbeef给出了一些提示,但它仍然不必要地模糊不清。另请注意,在调试器中查看反汇编代码时,宏的名称将不可见。
  • 调用abort()更清楚地表明意图。这不仅适用于代码本身,也适用于二进制文件的可观察行为。假设操作在Unix机器上按预期执行,结果会得到一个SIGSEGV,这是一个指示内存损坏的信号。另一方面,abort()导致SIGABRT,表示程序异常终止。除非导致致命错误的原因确实是内存损坏,否则在这种情况下抛出SIGSEGV会掩盖程序失败的原因,并可能误导开发人员试图查找错误。当你认为信号可能没有被调试器捕获时,这是特别微妙的,而是由自动信号处理程序捕获,然后可能会调用不合适的代码进行错误处理。

因此,如果宏的唯一目的是发出致命错误信号(顾名思义),调用abort将是一个更好的实现。

答案 2 :(得分:1)

取消引用无效指针(这是上面的代码试图做的)会导致未定义的行为。因此,系统可以做任何事情 - 它可能崩溃,它什么都不做,或demons can fly out of your nose。这个page是关于每个C程序员应该知道的关于未定义行为的一个很好的页面。

因此上面的代码是导致崩溃的错误方法。正如评论者指出的那样,最好调用abort()。