简体   繁体   中英

cout doesn't seem to work if used before NULL pointer de-referencing

I have the following C++ code. I am asking for a memory value from a NULL pointer. I mean, I am doing something like NULL-> kind of operation. I know this is an error . I am doing this operation inside the function 'funct' and I am printing the word Before Error before calling this function. As the program runs, this message must be printed and then the error must happen. Instead, directly the error happens. Why is it so?

Is it because the print statement and funct execution are independent and so they happen in different threads/cores and so the error precedes the printing ?

#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";

}

This is happening because cout output is buffered by default. Your program is getting a segmentation fault before it has a chance to flush the output buffer. You can disable buffering with this:

std::cout.setf(std::ios::unitbuf);

If you put that at the top of main() , you'll see the output before the segfault message. There are performance implications why you might not want to disable buffering, but in this case it'll show that the message really is being written.

You can also do a one-time flush of the buffer:

cout<<"Before Error";
std::cout.flush();
funct(205);

Dereferencing a null pointer is undefined behavior.

The behavior of your program is entirely undefined.

The compiler can, and will, do some crazy things when you have undefined behavior.

Reasoning about a program with undefined behavior is a futile effort.

That being said, you might want to ad a << endl to every time you call cout , as this will flush the buffer to stdout. This may (or may not, entirely dependent on the compiler and the optimizations being done!) have some type of impact on the behavior of your program. But this is just guessing. It might not even do what you want. It might make random information be sent to stdout. Reasoning about undefined behavior is very difficult.

For example, exploring your code on the assembly level with -O3 on GCC 6.2, the string '\\n END \\n' is not at all in the assembly (relevant but not complete assembly reproduced below).

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

Behaviour could differ based on platform (linux or windows) and compiler settings. On linux, printf/cout doesn't lead to immediate display after execution of statement. you may want to explicitly flush by using std::cout.flush(); or put the endl.

In fact, the message has been printed, you can check by using:

cout << "Before Error";
Sleep(5000);
funct(205);

After 5s, the error will be caught.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM