为什么printf()会阻止崩溃?

时间:2011-05-21 05:38:18

标签: debugging visual-c++

我一直在互联网上寻找这个问题的答案(见帖子主题)。我被问过两次这个确切的问题。一旦接受公司的采访,一次接受朋友的采访,我找不到我的生活答案。

在没有调试器的情况下进行调试时,我实际上遇到过多次错误,只是使用print语句来隔离错误。我不记得任何确切的情况,虽然我很肯定我经历过它。如果任何人都可以提供链接或引用或指向printf()源代码中的某些内容,当使用print语句调试代码时可能会导致错误停止发生,我将非常感谢良好的阅读。

谢谢你, Matthew Hoggan

我目前正在阅读所提供的链接,但为了进一步对话,我发布了一些我调查的弱尝试:

好吧,所以我已经开始玩自己尝试回答我自己的问题,但事情仍然不是100%清楚。下面是g ++编译器的输出,使用-S选项输出程序集而不是可执行文件。等效的C ++代码也发布在下面。我的目标是尝试重新创建一个简单的场景,然后根据指令尝试检测处理器级别可能发生的情况。所以,让我们说“调用printf”汇编代码,我假设是从存储在/ usr / lib或其他lib目录中的库文件链接,我试图访问NULL指针(不在代码中),或其他一些传统上会使程序崩溃的操作形式。我假设我必须找出printf正在做什么教学才能更深入地研究这个?

.file   "assembly_test_printf.cpp"

        .section    .rodata

.LC0:

    .string "Hello World"

    .text

.globl main

    .type   main, @function

main:

.LFB0:

    .cfi_startproc

    .cfi_personality 0x0,__gxx_personality_v0

    pushl   %ebp

    .cfi_def_cfa_offset 8

    movl    %esp, %ebp

    .cfi_offset 5, -8

    .cfi_def_cfa_register 5

    andl    $-16, %esp

    subl    $32, %esp

    movl    $0, 28(%esp)

    movl    $.LC0, (%esp)

    call    printf

    movl    28(%esp), %eax

    leave

    ret

    .cfi_endproc

.LFE0:

    .size   main, .-main

    .ident  "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"

    .section    .note.GNU-stack,"",@progbits

等效C ++代码:

#include <stdio.h>

int main ( int argc, char** argv ) {

    int x = 0;

    printf ("Hello World"); 

    return x;
}

2 个答案:

答案 0 :(得分:8)

添加printf()有几个原因可以改变错误的行为。一些比较常见的可能是:

  • 更改执行时间(特别是对于线程错误)
  • 更改内存使用模式(编译器可能会更改堆栈的使用方式)
  • 更改寄存器的使用方式

例如,可以将未初始化的局部变量分配给寄存器。在添加printf()之前,使用未初始化的变量并获得寄存器中的垃圾值(可能是之前调用rand()的结果,因此它确实是不确定的)。添加printf()会导致寄存器在printf()中使用,而printf()总是会将该寄存器设置为0(或其他)。现在你的越野车程序仍然很忙,但行为不同。也许这种行为恰好是良性的。

答案 1 :(得分:1)

我之前见过它,例如在Java中,如果另一个线程试图访问假定已经创建的对象,则初始化代码不完整。 System.out.println()减慢了另一个线程的速度,足以完成初始化。