这是什么意思?:*(int32 *)0 = 0;

时间:2013-08-23 16:13:38

标签: c

在下面的代码中,*(int32 *) 0 = 0;是什么意思?

void
function (void)
{
  ...

  for (;;)
     *(int32 *) 0 = 0;     /* What does this line do? */
}

一些注意事项:

  • 代码似乎无法访问,因为在该特定代码段之前有一个退出语句。
  • int32typedef,但你不应该太在意它。
  • 这段代码来自编译器中语言的运行时,对于任何感兴趣的人。

8 个答案:

答案 0 :(得分:33)

代码正在执行以下操作:

   for (;;) // while(true)
     *(int32 *) 0 = 0; // Treat 0 as an address, de-reference the 0 address and try and store 0 into it.

这应该是段错误,空指针取消引用。

修改

编译并运行以获取更多信息:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(void){
  *(int32_t *) 0 = 0;
  printf("done\n");
  return 0;
}

gcc -g null.c; ./a.out

Program received signal SIGSEGV, Segmentation fault.
0x00000000004004cd in main () at null.c:7
7         *(int32_t *) 0 = 0;

答案 1 :(得分:26)

由于OP声明代码是由经验丰富的编译工程师编写的,因此这可能是代码的意图:

  • *(int32 *) 0 = 0;被此特定C实现识别为导致未被C标准定义且此实现已知的行为非法的代码。
  • for (;;)另外表示此代码永远不会退出。
  • 编译器工程师知道优化器会识别此代码并推断它可能“被优化掉”,因为任何到达此代码的程序都被允许具有任何行为,因此优化器可以选择将其作为行为如果从未达到过代码。 1

如果您具有C实现的内部操作的特定知识,那么这种推理可能。编译器工程师可能包含在C实现的特殊标头中,可能是为了标记某些代码(例如abort调用后的代码)从未到达。它绝不应该用于正常的编程。


1 例如,请考虑以下代码:

if (a)
    for (;;)
        *(int 32 *) 0 = 0;
else
    foo();

编译器可以识别允许then子句具有任何行为。因此,编译器可以自由选择它具有的行为。为简单起见,它选择它具有与foo();相同的行为。然后代码变为:

if (a)
    foo();
else
    foo();

可以进一步简化为:

foo();

答案 2 :(得分:22)

事实上,这段代码seg-faulting并没有解释为什么它存在=)

我认为这是来自某些MCU的运行时间...并且它的存在是因为如果程序执行将到达这一点,这样的指令将启动MCU的软件复位,因此程序将重新启动(这是嵌入式中的常见做法)开发)或者,如果MCU配置了硬件看门狗,则由于硬件看门狗和永不结束循环而强制MCU重启。

此类构造的主要目标是调用可由OS或硬件处理以启动某些操作的中断。

知道它的x86将取决于CPU模式......在实模式下如果没有看门狗就不会立即发生任何事情,在地址0处有一个“除以0”处理程序的地址,所以如果它是一些旧的MS-DOS或嵌入式x86运行时它会将'Divide by 0'处理程序的地址更改为0,因此只要它发生并且此中断未被屏蔽,CPU将跳转到位置0:0并且可能只是重新启动,因为非法指令..如果它受到保护或VM x86代码,那么它是一种通知操作系统或任何其他主管在运行时出现问题的方法,软件应该在外部被“杀死”。

答案 3 :(得分:6)

for(;;)相当于while(1)

*(int32 *) 0 = 0;将0写入一个取消引用的空指针,该指针预计会导致崩溃,但实际上在某些编译器上实际上不会:Crashing threads with *(int*)NULL = 1; problematic?

答案 4 :(得分:3)

这是一个未定义行为的无限循环(取消引用空指针)。它可能会因* n * x上的段错误或Windows上的访问冲突而崩溃。

答案 5 :(得分:3)

Mike的评论非常正确:它在地址0处存储了VALUE零。

在大多数机器上都会崩溃。

答案 6 :(得分:3)

原始IBM PC stored the interrupt vector table in the lowest 1 KiB of memory。因此,实际上在这种架构上将32位值写入地址0会覆盖INT 00h的地址。 INT 00h looks unused in the PC.

基本上任何现代的东西(意思是x86 / x86-64在受保护的模式下运行的任何东西),它会触发分段错误,除非你在环中0(内核模式),因为您正在进程的允许地址取消引用范围之外。

由于取消引用是未定义的行为(如前所述),因此分段错误是处理该情况的完全可接受的方式。如果您知道在目标体系结构上零地址解引用会导致分段错误,那么这似乎是让应用程序崩溃的非常可靠的方法。如果exit()返回,那可能就是你想要做的事情,因为有些事情发生了可怕的错误。代码来自特定编译器的运行时意味着编写它的人可以利用编译器和运行时内部工作的知识,并根据特定目标体系结构的行为进行定制。

答案 7 :(得分:1)

可能是编译器不知道exit()没有返回,但它确实知道这个构造不会返回。