“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Different from Java’s exception handling mechanism, when you use C, you are more exposed to the error code-based exception mechanism. In simple terms, when a function is called with an exception, the program does not jump to a unified exception handling place, but instead returns an integer error code.

This function is defined as follows, for example, to open a file

int open(const char *pathname, int flags);
Copy the code

The open function returns a file descriptor (greater than 0) on success or -1 on failure. For developers, knowing that the file opened failed without knowing the exact reason can actually be a variety of reasons, such as:

  • File does not exist
  • The current process does not have read and write permission on the file

So how do you know what’s wrong? This requires the errno mechanism provided by the system.

errno

Errno is a global integer variable defined in the errno. H header that represents the last error that occurred at this time. You can get this value by referring to the errno. H header edge in your code.

As shown in the following demo, we try to open a file that does not exist:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>

int main(a) {
    int fd;
    fd = open("/test.log", O_RDONLY);
    if (fd == - 1) {
        printf("open failed, errno: %d\n", errno);
    }
    return 0;
}
Copy the code

Run the program and the output looks like this:

open failed, errno: 2
Copy the code

You can see that the error code is 2, so how do you know what the error code means?

We can get error messages in the following ways

moreutils

  1. Install moreutils
apt install moreutils
Copy the code
  1. runErrno error codeView specific error information

As you can verify, error code 2 indicates that the current file or directory does not exist, as you would expect

perror

Use the perror function defined in stdio.h to print error messages directly on standard output

The function definition is shown below, and we can append our own error message to the error message.

void perror(const char *s);
Copy the code

Demo:

int main(a) {
    int fd;
    fd = open("/test.log", O_RDONLY);
    if (fd == - 1) {
        perror("open failed");
    }
    return 0;
}
Copy the code

strerr

If we just need to get the text of the error code to log, we can use the strerr function, which is defined in String.h

Demo:

int main(a) {
    int fd;
    fd = open("/test.log", O_RDONLY);
    if (fd == - 1) {
      char* err_msg = strerror(errno);
      printf("%s\n", err_msg);
    }
    return 0;
}
Copy the code

The output

Is thread-safe?

Believe is more sensitive to concurrency problem students have realized a problem: the errno global variable is an integer, that if multiple threads execute system calls at the same time, and all failed for any reason, will be led to the incorrect information of the other threads are all the last thread to overwrite errors? And will there be thread safety issues?

Errno is actually defined as a thread-local variable, similar to the concept of ThreadLocal in Java, where each thread has its own errno variable and different threads do not interact with each other.

conclusion

  • Errno represents the specific error message that occurred the last time the function was called
  • For system calls we can passperrorPrint an error message,strerrorGets the corresponding error message text
  • errnoAre thread-local variables, each thread has its ownerrnoIs therefore thread-safe

Matters needing attention

  • Don’t use it directlyerrnoDetermine the success of the function call, and should determine the return result of the function before usingerrnoGet the correct error message. (errnoSave the error code of the last call failed.