我有以下C ++代码。我要求NULL指针的内存值。我的意思是,我正在做类似 NULL-> 类型的操作。 我知道这是一个错误。我在函数'funct'中执行此操作,我在调用此函数之前打印错误之前一词。程序运行时,必须打印此消息,然后必须发生错误。相反,直接发生错误。为什么会这样?
是否因为print语句和funct执行是独立的,因此它们发生在不同的线程/核心中,因此错误在打印之前?
#include <iostream>
#include <string>
using namespace std;
struct A
{
int a;
};
void funct(int a)
{
A *obj;
obj = NULL;
cout<<"Value is "<<obj->a;
}
int main()
{
cout<<"Before Error";
funct(205);
getchar();
cout<<"\n END \n";
}
答案 0 :(得分:1)
这种情况正在发生,因为cout
输出默认是缓冲的。您的程序在有机会刷新输出缓冲区之前会遇到分段错误。您可以使用以下命令禁用缓冲:
std::cout.setf(std::ios::unitbuf);
如果您将其放在main()
的顶部,则会在segfault消息之前看到输出。您可能不希望禁用缓冲,这会影响性能,但在这种情况下,它会显示消息确实正在写入。
您也可以一次性刷新缓冲区:
cout<<"Before Error";
std::cout.flush();
funct(205);
答案 1 :(得分:1)
取消引用空指针是未定义的行为。
程序的行为完全未定义。
当你有未定义的行为时,编译器可以而且会做一些疯狂的事情。
关于具有未定义行为的程序的推理是徒劳的。
话虽如此,您可能希望每次调用<< endl
时都要cout
,因为这会将缓冲区刷新到标准输出。这可能(或可能不完全取决于编译器和正在进行的优化!)对程序的行为产生某种影响。但这只是猜测。它甚至可能不会做你想要的。它可能会将随机信息发送到stdout。关于未定义行为的推理非常困难。
例如,在GCC 6.2上使用-O3
在汇编级别上探索代码时,字符串'\ n END \ n'在程序集中根本不存在(相关但不完整的程序集在下面重现)。 / p>
funct(int):
mov eax, DWORD PTR ds:0
ud2
.LC0:
.string "Before Error"
main:
mov edi, OFFSET FLAT:std::cout
sub rsp, 8
mov esi, OFFSET FLAT:.LC0
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
mov edi, 205
call funct(int)
sub rsp, 8
mov edi, OFFSET FLAT:std::__ioinit
call std::ios_base::Init::Init()
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:std::__ioinit
mov edi, OFFSET FLAT:std::ios_base::Init::~Init()
add rsp, 8
jmp __cxa_atexit
答案 2 :(得分:0)
行为可能因平台(linux或Windows)和编译器设置而异。在linux上,printf / cout在执行语句后不会立即显示。 您可能希望使用std :: cout.flush();或者把结束。
答案 3 :(得分:0)
事实上,邮件已打印,您可以使用以下方式进行检查:
cout << "Before Error";
Sleep(5000);
funct(205);
5秒后,错误将被捕获。