Chinaunix首页 | 论坛 | 博客
  • 博客访问: 221555
  • 博文数量: 19
  • 博客积分: 45
  • 博客等级: 民兵
  • 技术积分: 241
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-23 20:00
个人简介

如明日将死那样生活,如永远不死那样求知。

文章分类

全部博文(19)

文章存档

2018年(2)

2017年(3)

2015年(2)

2013年(11)

2012年(1)

我的朋友

分类: LINUX

2013-10-14 11:33:34

errno

关于errno,在使用时需要
#include

我们看一下/usr/include/errno.h,它 include 了 ,在这个文件里,你会找到errno的定义
  1. /* When using threads, errno is a per-thread value. */
  2. # define errno (*__errno_location ())
errno所以不是个变量,是个宏来的,而且是支持多线程的。
所以,在出错的情况下,如果需要多次使用到错误码,一般是用一个变量保存下errno,因为第二次使用errno时,是再一次调用了__errno_loaction()函数。同样,对errno赋值也是没有什么意义的。(关于这一点,我的认识是错误的。对errno赋值以后,perror打印内容是会发生变化的,errno的值也是会发生变化的,至于原因,刚才在linux内核源码里搜了一下,没找到perror的实现,因为看到内核里也有用perror的地方,所以觉得内核也应该有perror函数的实现。抽空会进一步研究,同时伏望高手不吝赐都啊!抽空看了一下,请见后面附一

在linux内核源码/usr/src/linux/arch/um/os-Linux/user_syms.c中,有
  1. EXPORT_SYMBOL_PROTO(__errno_location);
在这个文件中往上走几行,你会看见
  1. /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
  2.  * However, the modules will use the CRC defined *here*, no matter if it is
  3.  * good; so the versions of these symbols will always match
  4.  */
  5. #define EXPORT_SYMBOL_PROTO(sym) \
  6.     int sym(void); \
  7.     EXPORT_SYMBOL(sym);
注释已经很详尽了。不擅长英文的话,可以登陆 dict.youdao.com

EXPORT_SYMBOL是用来导出符号到内核符号表的,导出的符号可以被其他模块使用,当然使用之前最好还是声明一下的吧。
另外还有一个 EXPORT_SYMBOL_GPL,EXPORT_SYMBOL_GPL的特点是只适用于包含GPL许可权的模块。
作为图懒省事的现代人,我一般就用EXPORT_SYMBOL。

附一:errno可以被赋值的分析

先写一个小例子,就叫 a.c 吧:

  1. #include <stdio.h>
  2. #include <errno.h>

  3. int main()
  4. {
  5.     int a = 0;
  6.     int i = 0;
  7.     int *p = NULL;

  8.     for (i = 0; i < 128; i++) {
  9.         errno = i;
  10.         a = errno;
  11.         printf("a = %d\n", a);
  12.         perror("abc");
  13.     }
  14.     a = errno;
  15.     printf("a = %d\n", a);
  16.     return 0;
  17. }
编译执行以后,结果如下(避免太长,只粘贴一小部分):
a = 0
abc: Success
a = 1
abc: Operation not permitted
a = 2
abc: No such file or directory
a = 3
abc: No such process
a = 4
abc: Interrupted system call
a = 5
abc: Input/output error
…………

貌似errno这个宏可以被赋值,颠覆了我纯真的思想。其实errno这相做完宏替换以后,上面第11行代码是
  1. (*__errno_location ()) = i;
有兴趣的可以用 以下语句来看一下。
  1. gcc a.c -E -o a.i

  2. cat a.i
  3. vi a.i
现在我们在 a.c里加几行代码,修改如下:
  1. #include <stdio.h>
  2. #include <errno.h>

  3. int main()
  4. {
  5.     int a = 0;
  6.     int i = 0;
  7.     int *p = NULL;

  8.     for (i = 0; i < 128; i++) {
  9.         errno = i;
  10.         a = errno;
  11.         printf("a = %d\n", a);
  12.         perror("abc");
  13.         p = __errno_location();
  14.         printf("p = %p\n", p);
  15.         printf("*p = %d\n", *p);
  16.     }
  17.     return 0;
  18. }
编译完执行,发现 p 的地址每次都不会变。所以 errno 被赋值的时候,调用 __errno_loaction() 返回了一个内存地址,这块内存应该是由操作系统维护的,每次errno发生变化,只是会写到这块内存空间上。
那么,这块内存是什么时候分配的呢?errno最早的时候是 int errno;  现在却可以支持多线程了。
个人猜测:对于线程来说,基本上不拥有系统资源,但还是需要一些必不可少的能够保证其独立运行的资源的。个人觉得,这部分资源就包含了要分配给errno的4个字节的空间。也就做到了多线程支持。
具体评判我的猜测是否正确,还得进一步看pthread族的函数了。
先到这里吧,以后有空看看。呵呵。

先感慨一下,errno包括perror啥的经常用,但从来没想过去看看里面怎么回事,很多东西都是想当然的。实践出真知啊!
当然对于很多东西其实我还是觉得,也没必要弄清楚到哪个地步,能用也就可以了。只是今天突然发现了一些以前想当然的东西可能别我乾坤,虽然还是觉得对于有些问题能用就行了,但有一样感触就是:不管做什么事,都得认真!


阅读(6893) | 评论(0) | 转发(0) |
0

上一篇:Linux常用命令

下一篇:sctp通信

给主人留下些什么吧!~~