问题
As many young programmers do, I learned the usefulness of inserting numerous print-to-console statements of "here1," "here2," and so on at different points in code to figure out when my programs are going awry. This brute force debugging technique has saved me many, many times throughout my CS studies. However, when I started programming in C, I stumbled onto an interesting problem. If I were to try and run
void* test;
printf("hello world");
test[5] = 234;
Of course I get a segfault for not malloc'ing memory for testChar. However, you would think logically that "hello world" would be printed before the seg fault happens, since that is the flow of the code, but in my experience, it is always the case that the seg fault happens first, and "hello world" is never printed to the console at all. (I wasn't able to test this exact example, but I have run into this sort of situation many times using gcc on a linux box.) I'm guessing this has to do with either the compiler rearranging some things and/or printf using some sort of buffer that is flushed asynchronously and therefore not being immediate. This is entirely speculation on my part because I honestly don't know why it happens. In any other language that I have used, no matter what problem the "testChar =..." line caused, the "hello world" would still be printed, and thus I could determine where the problem is.
My question is why does this happen when I'm programming C? Why isn't the hello world printed first? And secondly, is there a better C programming debugging technique than this that accomplishes the same basic thing? As in, an easy/intuitive way to find the line of code that is a problem?
Edit: I gave a working example by accident haha. What I have now should cause a segfault. It's funny how usually when I don't want a segfault I get one, and now when I actually wanted one I wrote legal code!
回答1:
The code you posted is perfectly legal and should not cause a segfault - there is no need to malloc anything. Your problem must lie somewhere else - please post the smallest example of code that causes the problem.
Edit: You have now edited the code to have a totally different meaning. Still, the reason that "hello world" is not displayed is that the the output buffer has not been flushed. Try addinig
fflush( stdout );
after the printf.
Regarding locating the source of the problem you have a couple of choices:
- liberally sprinkle printfs through your code using the
__FILE__
and__LINE__
C macros - learn to use your debugger - if your platform supports core dumps, you can use the core image to find where the error is.
回答2:
printf
writes to stdout, which is buffered. Sometimes that buffer doesn't get flushed before your program crashes so you never see the output. Two ways to avoid this:
- use
fprintf( stderr, "error string" );
since stderr is not buffered. - add a call to
fflush( stdout );
after the printf call.
As Neil and others have said, the code as written is fine. That is, until you start modifying the buffer that testChar
points to.
回答3:
"As in, an easy/intuitive way to find the line of code that is a problem?"
Use gdb (or any other debugger).
To find where your program seg faults you compile it with -g
option (to include debugging symbols) run your application from gdb, it will stop on seg fault.
You can then look at backtrace with bt
command to see at which point you got the seg fault.
example:
> gdb ./x
(gdb) r
Starting program: /proj/cpp/arr/x
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x000019a9 in willfail () at main.cpp:22
22 *a = 3;
(gdb) bt
#0 0x000019a9 in willfail () at main.cpp:22
#1 0x00001e32 in main () at main.cpp:49
(gdb)
回答4:
The output is buffered by default, the segfault occurs before the output is actually written to stdout. Try:
fprintf(stderr, "hello, world\n");
(stderr is unbuffered by default.)
回答5:
This code shouldn't segfault. You're just assigning a pointer to a literal string to a pointer variable. Things would be different if you were e.g. using strcpy
to copy stuff with an invalid pointer.
The message not appearing may be due to buffered I/O. Print a newline character \n
or call fflush
to flush the output buffer.
回答6:
You have two problems. The first is that your (original) code won't segfault. It's perfectly valid to assign that string constant to a char pointer. But let's leave that aside for now and pretend you had put something there that would segfault.
Then it's usually a matter of buffers, the one in the C runtime library and the one in the OS itself. You need to flush them.
The easiest way to do that was (in UNIX, not entirely certain about the fsync
in Linux but you should be guaranteed that this wil happen eventually unless the system itself goes down):
printf ("DEBUG point 72\n"); fflush (stdout); fsync (fileno (stdout));
I've done this often in UNIX and it ensures that the C runtime libraries are flushed to UNIX (fflush
) and the UNIX buffers are sync'ed to disk (fsync
), useful if stdout is not a terminal device or you're doing it for a different file handle.
回答7:
void* test;
printf("hello world");
test[5] = 234;
Its likely that "hello world" is being buffered by the system somewhere and is not immediately printed to the screen. Its stored waiting for a chance for whatever process/thread/whatever is in charge of screen writing can have a chance to process it. And while its waiting (and possibly buffering other data to output) you're function is finishing. It comes over the illegal access and segfaults.
来源:https://stackoverflow.com/questions/975448/c-programming-seg-faults-printf-and-related-quirks