When should I use perror("...") and fprintf(stderr, "...")? - c

Reading the man pages and some code did not really help me in
understanding the difference between - or better, when I should use - perror("...") or fprintf(stderr, "...").

Calling perror will give you the interpreted value of errno, which is a thread-local error value written to by POSIX syscalls (i.e., every thread has it's own value for errno). For instance, if you made a call to open(), and there was an error generated (i.e., it returned -1), you could then call perror immediately afterwards to see what the actual error was. Keep in mind that if you call other syscalls in the meantime, then the value in errno will be written over, and calling perror won't be of any use in diagnosing your issue if an error was generated by an earlier syscall.
fprintf(stderr, ...) on the other-hand can be used to print your own custom error messages. By printing to stderr, you avoid your error reporting output being mixed with "normal" output that should be going to stdout.
Keep in mind that fprintf(stderr, "%s\n", strerror(errno)) is similar to perror(NULL) since a call to strerror(errno) will generate the printed string value for errno, and you can then combined that with any other custom error message via fprintf.

They do rather different things.
You use perror() to print a message to stderr that corresponds to errno. You use fprintf() to print anything to stderr, or any other stream. perror() is a very specialized printing function:
perror(str);
is equivalent to
if (str)
fprintf(stderr, "%s: %s\n", str, strerror(errno));
else
fprintf(stderr, "%s\n", strerror(errno));

perror(const char *s): prints the string you give it followed by a string that describes the current value of errno.
stderr: it's an output stream used to pipe your own error messages to (defaults to the terminal).
Relevant:
char *strerror(int errnum): give it an error number, and it'll return the associated error string.

perror() always writes to stderr;
strerr(), used together with fprintf(), can write to any output - including stderr but not exclusively.
fprintf(stdout, "Error: %s", strerror(errno));
fprintf(stderr, "Error: %s", strerror(errno)); // which is equivalent to perror("Error")
Furthermore, perror imposes its own text formating "text: error description"

Perror function take more time to perform execution call goes from user space to kernal space wheras fprintf calls goest to api to kernal

Related

stdio to terminal after close(STDOUT_FILENO) behavior

I am wondering why uncommenting that first printf statement in the following program changes its subsequent behavior:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
//printf("hi from C \n");
// Close underlying file descriptor:
close(STDOUT_FILENO);
if (write(STDOUT_FILENO, "Direct write\n", 13) != 13) // immediate error detected.
fprintf(stderr, "Error on write after close(STDOUT_FILENO): %s\n", strerror(errno));
// printf() calls continue fine, ferror(stdout) = 0 (but no write to terminal):
int rtn;
if ((rtn = printf("printf after close(STDOUT_FILENO)\n")) < 0 || ferror(stdout))
fprintf(stderr, "Error on printf after close(STDOUT_FILENO)\n");
fprintf(stderr, "printf returned %d\n", rtn);
// Only on fflush is error detected:
if (fflush(stdout) || ferror(stdout))
fprintf(stderr, "Error on fflush(stdout): %s\n", strerror(errno));
}
Without that first printf, the subsequent printf rtns 34 as if no error occured even though the connection from the stdout user buffer to the underlying fd has been closed. Only on a manual fflush(stdout) does the error get reported back.
But with that first printf turned on, the next printf reports errors as I would expect.
Of course nothing is written to the terminal(by printf) after the STDOUT_FILENO fd has been closed in either case.
I know it's silly to close(STDOUT_FILENO) in the first place here; this is an experiment I stumbled into and thinking someone more knowledgeable in these areas may see something instructive to us in it..
I am on Linux with gcc.
If you strace the both programs, it seems that stdio works so that upon first write, it checks the descriptor with fstat to find out what kind of file is connected to the stdout - if it is a terminal, then stdout shall be line-buffered, if it is something else, then stdout will be made block-buffered. If you call close(1); before the first printf, now the initial fstat will return EBADF and as 1 is not a file descriptor that points to a character device, stdout is made block-buffered.
On my computer the buffer size is 8192 bytes - that many bytes can be buffered to be written to stdout before the first failure would occur.
If you uncomment the first printf, the fstat(1, ...) succeeds and Glibc detects that stdout is connected to a terminal; stdout is set to line-buffered, and thus because printf after close(STDOUT_FILENO)\n ends with newline, the buffer will be flushed right away - which will result in an immediate error.

Do ferrors carry through multiple writes?

Does the ferror in this example check check both fprintfs for error, or just the second one?
FILE * myout;
if ((myout = fopen("Assignment 11.txt", "a")) != NULL)
{
fprintf(myout, "First print ", str1);
fprintf(myout, "Second print", str1);
if (ferror(myout))
fprintf(stderr, "Error printing to file!");
fclose(myout);
}
If an error occurs, it won't be reset unless clearerr is called on your stream, so yes, an error occuring on any of both writes is recorded.
from ferror manual page:
The function ferror() tests the error indicator for the stream pointed to by stream, returning nonzero if it is set. The error indicator can only be reset by the clearerr() function.
But you could also simply use fprintf return code to see if something went wrong:
If an output error is encountered, a negative value is returned.
(fprintf manual page)
Like this (Thanks Jonathan for pointing out the errors in the original post):
if (fprintf(myout, "First print %s\n", str1)<0) fprintf(stderr, "Error printing to file #1!");
if (fprintf(myout, "Second print %s\n", str1)<0) fprintf(stderr, "Error printing to file #2!");

Difference between perror() and printf()

I had read that both perror() and printf() write to the terminal screen. But perror() writes to stderr while printf() writes to stdout. So, to print errors why is perror() used when printf() can do it.
printf() cannot write to stderr. fprintf() can. perror() always does.
There is no requirement that writing to either stdout or stderr writes to a terminal screen - that is up to the implementation (since not all systems even have a terminal). There is also no requirement that writing to stdout and stderr results in writing to the same device (e.g. one can be redirected to a file, while the other is redirected to a pipe).
perror() will be implemented with built-in knowledge of the meanings of error codes, represented by the static errno, which is used by various functions in the standard library to report error conditions. The meanings of particular values are implementation defined (i.e. they vary between compilers and libraries).
Because there could be configurations where you want stderr printed to the console but the other output not printed at all (for example, to remove verbosity). In other cases you may need to redirect stderr to write to a file, this is useful when you are in production and that file can be used to understand what went wrong on a remote computer you can't debug yourself.
In general, you gain more control on how console outputs are treated depending on their type.
See this answer to understand how you can do stream redirection in code.
Or, see this link on how you can force stream redirection to file or ignore a stream on an already compiled program (while invoking it in bash)
In addition to other answers, you might use fprintf(3) on stderr and errno(3) with strerror(3) like
fprintf(stderr, "something wrong: %s\n", strerror(errno));
On GNU libc systems (many Linux systems), you could use instead %m conversion specifier instead:
fprintf(stderr, "something wrong: %m\n");
You conventionally should output error messages to stderr (see stderr(3)); see also syslog(3) to use system logging.
Don't forget to end the format string with \n since stderr is often line buffered (but sometimes not) or else use fflush(3)
For example, you might want to show both the error, the filename and the current directory on fopen failure:
char* filename = somefilepath();
assert (filename != NULL);
FILE* f = fopen(filename, "r");
if (!f) {
int e = errno; // keep errno, it could be later overwritten
if (filename[0] == '/') /// absolute path
fprintf(stderr, "failed to open %s : %s\n", filename, strerror(e));
else { // we also try to show the current directory since relative path
char dirbuf[128];
memset (dirbuf, 0, sizeof(dirbuf));
if (getcwd(dirbuf, sizeof(dirbuf)-1))
fprintf(stderr, "failed to open %s in %s : %s\n",
filename, dirbuf, sterror(e));
else // unlikely case when getcwd failed so errno overwritten
fprintf(stderr, "failed to open %s here : %s\n",
filename, sterror(e));
};
exit(EXIT_FAILURE); // in all cases when fopen failed
}
Remember that errno could be overwritten by many failures (so we store it in e, in the unlikely case that getcwd fails and overwrite errno).
If your program is a deamon (e.g. has called daemon(3)) you'll better use system log (i.e. call openlog(3) after calling daemon) since daemon can redirect stderr to /dev/null
There are three standard stream stdin stdout stderr. You can refer to know what is important of different stream.
For error messages and diagnostics ,stderr is used , to print on stderr
Perror is used. printf can not do that. Perror is also used to handle errors from system call
fd = open (pathname, flags, mode);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
You can refer more about this in book The linux programming interface
void perror(const char *s)
Perror prints message in following sequence :
argument of s , a colon , a space , a short message concerning error whose error code currently in errnoand newline
In standard C if s is null pointer than only message will be printed . other things will be ignored
To understand more you can also refer page 332 of The complete reference C
A big advantage of using perror():
It is sometimes very useful to redirect stdout into /dev/null to only have access to errors since the verbosity of stdout might hide the errors that we need to fix.
perror
The general purpose of the function is to halt the execution process due to an error. The error message produced by perror is platform-depend. You can also print your own error message also.
printf
The general purpose of the function is to print message user defined and continue the execution.

Does EOF set errno?

I always struggle with return values of system calls - they are just so inconsistent!
Normally I check if they are NULL or -1 and then call perror. However, for fgets, the man page says:
gets() and fgets() return s on success, and NULL on error or when end of file occurs while no characters have been read.
which means the return value NULL is not necessarily an error - it can also be EOF. Is errno set when the end of file is reached? Can I still call perror in this case?
If not, what is the common way to tell if the call returned an error versus EOF. I want to use perror with NULL string for errors and a custom string for EOF.
Use ferror and feof to distinguish between error and EOF. There's no general way to find out exactly what the error was, if there was an error, but you can tell that there was one.
Standard C (f)gets (and (f)getc) are not required to set errno, although a conforming library implementation can set errno to a non-zero value pretty much at will.
Posix does requires that (f)get{c,s} set errno on read errors, but that only helps you after you have determined that there was a read error (by calling ferror). It's also important to remember that library functions never set errno to 0, but may set errno to a non-zero value even if no error occurs. So you cannot test errno as a replacement for checking the error return of any library function, including fgets. And since end-of-file is not an error, errno will (probably) not be modified on EOF, so its value in that case is meaningless.
According to fputs own documentation, yes, EOF does set errno. The man pages infer it indirectly as opposed to stating it outright, which hopefully will be amended. The function fputs returns an integer that will either be positive on success or EOF on failure. So the key to error handling fputs is to setup a code block that checks the return value of fputs as it is being called. The following is a snippet of how I've been taught to handle fputs errors.
if (fputs(buffer, stdout) == EOF)
{
fprintf(stderr, "fputs returned EOF: %s\n", strerror(errno));
// .. and now do whatever cleanup you need to do.
// or be lazy and exit(-1)
}
Here I am writing the contents of buffer to standard output and checking to see if fputs returns EOF. EOF indicates an error code was set, so as long as you follow the documentation on the man pages for fputs, you should be able to create a bunch of if statements to check the various error codes errno can be set to.
(1) What is buffer? Some character array I declared elsewhere.
(2) What does fprintf do? It prints output to a passed in file descriptor, which is in this case standard error (stderr... it prints to console like stdout, but for errors).
(3) What is strerror? It is a function defined in the string.h header that prints error information for the passed in error code. It has information for every single error code that errno can be set to. The header string.h should NOT be confused with strings.h, which is a BSD linux header file that does not contain strerror(3).
Edit: Ok, I messed up. You were looking for an answer on fgets, not fputs.
To check for an error on fgets, do the following
if (fgets(buffer, BUF_SIZE, myFile) == NULL)
{
// print out error as a string to stderr
fprintf(stderr, "fgets error occurred: %s\n", strerror(errno));
// do cleanup
}
// special: you also need to check errno AFTER the if statement...
The thing is, the only way you are getting an error on this is if the stream becomes unreadable, which is either due to permissions or trying to read something that is in write mode. In the case of a network, it may be possible for something to cut off your connection in the middle of reading, in which case you need to check the error code after the fgets if statement as well. But it will set the error code if something went wrong.
At least that is if the man pages are correct. See the linux man pages for more details. Only error code that can be set is the "I can't read this thing" code, which is errno == EBADF

How to find the error returned by read()?

I am reading data sent by the parent process using pipe.
Parent process close the read end and write data on the write end of pipe. Similarly, child closes write end and read data from read end.
But in my case, read returned the "-1" which is error value.
How should I find that, which error(like EAGAIN, EBADF, EIO ) has been occurred in read call?
Thanks
How should i found that, which error(like EAGAIN, EBADF, EIO ) has
been occurred in read call?
Print errno. An even better option is to do a perror, right after the call.
if (read(...) < 0)
perror("read");
Or use strerror if you need to get the message yourself:
printf("%s\n", strerror(errno));
Note you'll need to #include <errno.h> if you use errno directly.
If you use linux the following code will print a related error message as a string:
printf("%s", strerror(errno));
A non-portable glibc extension, try simply: printf( "%m" );
(Glibc extension; supported by uClibc and musl.) Print output of strerror(errno). No argument is required.

Resources