Article 3: errno. h Quick Start

Source: Internet
Author: User

Introduction:

Header file errno. h defines a Global Macro errno, Which is expanded into an int type "Left value", which means that the macro errno is not necessarily an object identifier, it can also be expanded into a "Left value" that can be modified returned by the function, such as int * errno, you can understand it as a global int variable for the moment (although it is wrong, it is easy to understand ).

 

In short, errno. h only provides an error reporting mechanism. For example, if an error occurs when a function calls fopen (), it may modify the value of errno, so that external code can distinguish fopen () by judging the value of errno () whether an error occurs during internal execution and determines the specific error type based on the errno value.
Let's take a look at a piece of code, Demo1:

#include<stdio.h>#include<errno.h>int main ( int argc, char *argv[] ){//try to open file "whatever.txt". when you run this demo,make sure the file is NOT existed..。FILE *fp = fopen("whatever.txt","r");if(fp ==NULL){printf("Can not open file\n");printf("errno value: %d, it means: %s",errno, strerror(errno));}return 0;}

The program will output:

Can not open fileerrno value: 2, it means: No such file or directory

Strerror is a function defined by stdio. h In the standard library. It is used to return the meaning represented by the error code. As shown in Demo1, we use fopen (also defined in stdio. h) to open a non-existing file. Therefore, the returned fp is a null pointer. When fopen fails to open the file, it will modify the errno value. In Demo1, fopen fails because the file does not exist. Therefore, fopen will change the value pointed to by errno to 2, through stderror, we can see that error code 2 means "No such file or directory ".

Handsome, it seems that errno is used to report errors, which is both convenient and simple, but the actual application is far less simple than Demo1. Try Demo2:

#include<stdio.h>#include<errno.h>#include<math.h>int main ( int argc, char *argv[] ){/*try to open file "whatever.txt". when you run this demo,make sure the file is NOT existed...*/FILE *fp = fopen("whatever.txt","r");if(fp ==NULL){printf("Can not open file\n");int root = sqrt(123568 -123668 );printf("errno value: %d, it means: %s",errno, strerror(errno));}return 0;}

The program will output:

Can not open fileerrno value: 33, it means: Numerical argument out of domain

This is completely different from the expected error message, because when the sqrt function gets an invalid parameter, it changes the errno value to 33, covering the error code set by fopen. Therefore, a safer encoding method using errno is to view its value before the next library function call, do not assume that a database function does not modify the value of errno because it seems simple. It will die badly ...... If you must call other library functions before checking errno, a safe way is to save the value of errno to a temporary variable and then call the required library function, after the processing is completed, errno is restored to the previous value. For example, Demo3:

#include<stdio.h>#include<errno.h>#include<math.h>double getSqrt(double value){//1、save last errno to a temp variableint tmpErrno = errno;//2、set errno to 0errno = 0;double root = sqrt(123568 -123668 );printf("I changed errno to '%d' sliently...but it's safe \n",errno);//3.restore errnoerrno = tmpErrno;return root;}int main ( int argc, char *argv[] ){FILE *fp = fopen("whatever.txt","r");if(fp ==NULL){printf("Can not open file\n");getSqrt(-1);printf("errno value: %d, it means: %s",errno, strerror(errno));}return 0;}

The program will output:

Can not open fileI changed errno to '33' sliently...but it's safeerrno value: 2, it means: No such file or directory

Now, the output is as expected.
But ......
Is this really safe ?! Imagine that if errno is a global variable, wouldn't it end up in a multi-threaded environment ?! When thread A sets errno to 2 and does not execute the statement to view errors, thread B sets errno to 33. Then thread A starts to view errno and outputs error information, the output error is so crazy! Oh, no way to use this broken multi-thread!
But ......
You're worrying about it ...... As mentioned in the article, the macro errno can be expanded into a "Left value", such as int * getYourErrno (), so you can return a local variable in the thread in getYourErrno, in this way, no matter which thread modifies errno, it modifies its own local variables, so the problem we are worried about does not exist. Check the source code of errno. h.

/* Get the error number constants from the system-specific file.   This file will test __need_Emath and _ERRNO_H.  */#include <bits/errno.h>#undef__need_Emath#ifdef_ERRNO_H/* Declare the `errno' variable, unless it's defined as a macro by   bits/errno.h.  This is the case in GNU, where it is a per-thread   variable.  This redeclaration using the macro still works, but it   will be a function declaration without a prototype and may trigger   a -Wstrict-prototypes warning.  */#ifndeferrnoextern int errno;#endif

As mentioned above, if errno has not been defined, errno will be defined as "extern int errno;". If this is the case of multithreading, it will be a tragedy. Don't worry about crying first, let's go to the front to see if it has been defined. The previous Code includes a file named bits/errno. the header file of h is very "sinister". Go in and see:

# ifndef __ASSEMBLER__/* Function to get address of global `errno' variable.  */extern int *__errno_location (void) __THROW __attribute__ ((__const__));#  if !defined _LIBC || defined _LIBC_REENTRANT/* When using threads, errno is a per-thread value.  */#   define errno (*__errno_location ())#  endif# endif /* !__ASSEMBLER__ */

Really bad ...... If macro _ extends er __is not specified, the intermediate code will be executed, if you do not define _ LIBC or define _ LIBC_REENTRANT, they will define errno AS _ errno_location. Once you see that macro _ LIBC_REENTRANT contains "reentrant (re-import) it's not a good thing ...... No, the name is related to multiple threads. If you want to use errno correctly in a multi-threaded environment, make sure that _ javaser _ is not defined, besides, _ LIBC is not defined or _ LIBC_REENTRANT is defined.
You can write a program to check the macro settings in your development environment:

#include <stdio.h>#include <errno.h>int main( void ){#ifndef __ASSEMBLER__        printf( "__ASSEMBLER__ is NOT defined!\n" );#else        printf( "__ASSEMBLER__ is defined!\n" );#endif#ifndef __LIBC        printf( "__LIBC is NOT defined\n" );#else        printf( "__LIBC is defined!\n" );#endif#ifndef _LIBC_REENTRANT        printf( "_LIBC_REENTRANT is NOT defined\n" );#else        printf( "_LIBC_REENTRANT is defined!\n" );#endif        return 0;}

My output:

_ASSEMBLER__ is NOT defined!__LIBC is NOT defined!_LIBC_REENTRANT is NOT defined!

Ha! It seems that I can safely use errno under multiple threads. If your default environment is not available, define _ LIBC_REENTRANT in makefile!
OK. The introduction to errno. h is over. Take a rest and take a rest!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.