errno 是个啥?

------------------------------------------------------------
author:      hjjdebug
date:        2024年 07月 14日 星期日 10:39:52 CST
description: errno 是个啥?
------------------------------------------------------------

linux 中, errno 定义在<errno.h>中, 原文如下:

/* The error code set by various library functions.  */
extern int *__errno_location (void) __THROW __attribute_const__;
# define errno (*__errno_location ())

可见:

1. errno 是一个宏

   #define errno  blablabla....

2. errno 是一个函数调用返回的整数值.

# define errno (*__errno_location ())
函数调用返回的是一个整形数地址. 解引用得到数值

3. __errno_location() 是个啥?

这是个库函数, 我这里不准备详细研究这个函数, 但也要大致研究一下这个库函数的返回值, errno.

4. errno 是一个全局变量吗?不是,它是线程变量.

    全局变量是属于进程的,而errno 是属于线程.
    进程变量在多线程环境下有安全性问题. 即你刚刚写给它一个值, 再读回来可能就不是你写的那个值了.
    而线程变量, 其它线程是不会干扰到你的线程运行的.
    下面我们给出 errno 是线程变量的测试程序.
    说明errno 是一个线程安全变量, 每一个线程都有一个自己的errno 变量与之对应.

$ cat main.cpp 
#include <stdio.h>   // for printf
#include <errno.h>   // for errno
#include <pthread.h> // for pthread_create
#include <unistd.h> // for syscall
#include <sys/syscall.h>   // for __NR_gettid

#define NTHREADS 3
#define gettid() syscall(__NR_gettid)

void *thread_function(void *pData)
{
	int d=*(int *)pData;
	printf("thread_id:%ld,thread_self:%lx, addr(pData):%p,addr(d):%p,addr(errno):%p\n",gettid(), pthread_self(),pData,&d,&errno);
   return NULL;
}
int main()
{
   pthread_t thread_id[NTHREADS];
   int i, j;

   for(i=0; i < NTHREADS; i++)
   {
      pthread_create( &thread_id[i], NULL, thread_function, &i );
   }

   for(j=0; j < NTHREADS; j++)
   {
      pthread_join( thread_id[j], NULL);
   }
   return 0;
}

// $ ./errno 
// thread_id:4486,thread_self:7f9b37bf1700, addr(pData):0x7ffff95eee5c,addr(d):0x7f9b37bf0ed4,addr(errno):0x7f9b37bf1680
// thread_id:4487,thread_self:7f9b37260700, addr(pData):0x7ffff95eee5c,addr(d):0x7f9b3725fed4,addr(errno):0x7f9b37260680
// thread_id:4488,thread_self:7f9b368cf700, addr(pData):0x7ffff95eee5c,addr(d):0x7f9b368ceed4,addr(errno):0x7f9b368cf680
// 可见pData 是传来的变量i的地址,是进程变量
// d 是线程变量地址,errno也是线程变量地址,不同的线程,访问的是不同的地址,虽然它们的名字都叫d, errno
// thread_id 是系统分配的线程号, thread_self是线程的地址边界

5. 怎样得到errno 对应的错误信息?


可以用 strerror(errno) 函数, 该函数在 string.h 头文件中记录.
下面给出一个简单的errno 信息打印程序, 及运行结果
 

$ cat main.cpp 
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(void)
{
	for(int i=0;i<255;i++)
	{
		printf("errno:%d(%s)\n",i,strerror(i));
	}
	return 0;
}

运行结果, 发现错误号超过134, 都是unkown, 即系统未定义.
$ ./errno_str 
errno:0(Success)
errno:1(Operation not permitted)
errno:2(No such file or directory)
errno:3(No such process)
errno:4(Interrupted system call)
errno:5(Input/output error)
errno:6(No such device or address)
errno:7(Argument list too long)
errno:8(Exec format error)
errno:9(Bad file descriptor)
errno:10(No child processes)
errno:11(Resource temporarily unavailable)
errno:12(Cannot allocate memory)
errno:13(Permission denied)
errno:14(Bad address)
errno:15(Block device required)
errno:16(Device or resource busy)
errno:17(File exists)
errno:18(Invalid cross-device link)
errno:19(No such device)
errno:20(Not a directory)
errno:21(Is a directory)
errno:22(Invalid argument)
errno:23(Too many open files in system)
errno:24(Too many open files)
errno:25(Inappropriate ioctl for device)
errno:26(Text file busy)
errno:27(File too large)
errno:28(No space left on device)
errno:29(Illegal seek)
errno:30(Read-only file system)
errno:31(Too many links)
errno:32(Broken pipe)
errno:33(Numerical argument out of domain)
errno:34(Numerical result out of range)
errno:35(Resource deadlock avoided)
errno:36(File name too long)
errno:37(No locks available)
errno:38(Function not implemented)
errno:39(Directory not empty)
errno:40(Too many levels of symbolic links)
errno:41(Unknown error 41)
errno:42(No message of desired type)
errno:43(Identifier removed)
errno:44(Channel number out of range)
errno:45(Level 2 not synchronized)
errno:46(Level 3 halted)
errno:47(Level 3 reset)
errno:48(Link number out of range)
errno:49(Protocol driver not attached)
errno:50(No CSI structure available)
errno:51(Level 2 halted)
errno:52(Invalid exchange)
errno:53(Invalid request descriptor)
errno:54(Exchange full)
errno:55(No anode)
errno:56(Invalid request code)
errno:57(Invalid slot)
errno:58(Unknown error 58)
errno:59(Bad font file format)
errno:60(Device not a stream)
errno:61(No data available)
errno:62(Timer expired)
errno:63(Out of streams resources)
errno:64(Machine is not on the network)
errno:65(Package not installed)
errno:66(Object is remote)
errno:67(Link has been severed)
errno:68(Advertise error)
errno:69(Srmount error)
errno:70(Communication error on send)
errno:71(Protocol error)
errno:72(Multihop attempted)
errno:73(RFS specific error)
errno:74(Bad message)
errno:75(Value too large for defined data type)
errno:76(Name not unique on network)
errno:77(File descriptor in bad state)
errno:78(Remote address changed)
errno:79(Can not access a needed shared library)
errno:80(Accessing a corrupted shared library)
errno:81(.lib section in a.out corrupted)
errno:82(Attempting to link in too many shared libraries)
errno:83(Cannot exec a shared library directly)
errno:84(Invalid or incomplete multibyte or wide character)
errno:85(Interrupted system call should be restarted)
errno:86(Streams pipe error)
errno:87(Too many users)
errno:88(Socket operation on non-socket)
errno:89(Destination address required)
errno:90(Message too long)
errno:91(Protocol wrong type for socket)
errno:92(Protocol not available)
errno:93(Protocol not supported)
errno:94(Socket type not supported)
errno:95(Operation not supported)
errno:96(Protocol family not supported)
errno:97(Address family not supported by protocol)
errno:98(Address already in use)
errno:99(Cannot assign requested address)
errno:100(Network is down)
errno:101(Network is unreachable)
errno:102(Network dropped connection on reset)
errno:103(Software caused connection abort)
errno:104(Connection reset by peer)
errno:105(No buffer space available)
errno:106(Transport endpoint is already connected)
errno:107(Transport endpoint is not connected)
errno:108(Cannot send after transport endpoint shutdown)
errno:109(Too many references: cannot splice)
errno:110(Connection timed out)
errno:111(Connection refused)
errno:112(Host is down)
errno:113(No route to host)
errno:114(Operation already in progress)
errno:115(Operation now in progress)
errno:116(Stale file handle)
errno:117(Structure needs cleaning)
errno:118(Not a XENIX named type file)
errno:119(No XENIX semaphores available)
errno:120(Is a named type file)
errno:121(Remote I/O error)
errno:122(Disk quota exceeded)
errno:123(No medium found)
errno:124(Wrong medium type)
errno:125(Operation canceled)
errno:126(Required key not available)
errno:127(Key has expired)
errno:128(Key has been revoked)
errno:129(Key was rejected by service)
errno:130(Owner died)
errno:131(State not recoverable)
errno:132(Operation not possible due to RF-kill)
errno:133(Memory page has hardware error)
errno:134(Unknown error 134)
errno:135(Unknown error 135)
errno:136(Unknown error 136)
errno:137(Unknown error 137)
errno:138(Unknown error 138)
errno:139(Unknown error 139)
errno:140(Unknown error 140)
... 其后都是Unkown...

6. errno 在系统中是如何定义的?

请参考 errno 5 错误追踪

errno 5追踪._errno -5-CSDN博客

7. errno 的应用实例参考.


当一个系统调用或着库函数的调用失败时,将会由被调用函数设置错误代码errno。
当然你的函数在出错时也可以设置errno, 但应该保持与系统定义的意义一致. 不过一般你是不需要设置errno的
下面的程序演示了,只有在调用库函数不出错时(路径存在), 才能得到正确的可用内存数值.


$ cat main.cpp
#include <stdio.h>
#include <sys/statfs.h>
#include <errno.h>
#include <string.h>

int main()
{
	struct statfs buf;
// 文件路径不存在,打印可用内存不会有正确结果,
//	int ret=statfs("/home/hjj/notexist", &buf);
// 路径存在才会有正确输出, 这是我写本博客的初始原因
	int ret=statfs("/home/hjj/", &buf);
	printf("ret is %d\n",ret);
	if(ret<0)
	{
		printf("error:%d(%s)\n",errno,strerror(errno));
		return -1;
	}
	printf("free block avail:%ld(K bytes)\n",buf.f_bavail * buf.f_bsize/1024);

	return 0;
}

运行结果:
$ ./statfs
ret is 0
free block avail:21930648(K bytes)
与 $ df 显示的一致
文件系统           1K-块      已用      可用 已用% 挂载点
/dev/nvme0n1p3  83558648  57337440  21930648   73% /home

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值