C Programming: seg faults, printf, and related quirks

て烟熏妆下的殇ゞ 提交于 2019-12-10 10:20:18

问题


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:

  1. use fprintf( stderr, "error string" ); since stderr is not buffered.
  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!