无论何时,只要执行了系统调用或者库函数,检查调用的返回状态可以确定调用是否成功,这是一条编程铁律
系统调用是受控的内核入口
1. 系统调用将处理器从用户态切换到内核态,以便CPU访问受到保护的内核内存
2. 系统调用的组成是固定的,每个系统调用都由一个唯一的数字来标识
3. 每个系统调用可以辅之以一套参数,对用户空间与内核空间之间传递的信息加以规范
在Linux上,系统调用服务例程遵循的惯例是调用成功返回非负值;发生错误时,例程会对errno常量取反,返回一负值,C语言函数库的外壳函数随即再取反,将结果拷贝到errno,同时以-1作为外壳函数的值返回
获取glibc版本
1. 执行libc.so.6
2. 应用程序可以通过访问常量__GLIBC__和__GLIBC_MINOR__分别对应主版本号和副版本号
3. 调用函数gnu_get_libc_version(void)
-
#include <gnu/libc-version.h>
-
const char *gnu_get_libc_version(void);
-
/*Returns pointer to null-terminated, statically allocated string containing
-
GNU C library version number. PS: Thread safe*/
系统调用失败
系统调用失败时,会将全局整型变量errno设置为一个正值,以标识具体的错误。如果调用系统调用和库函数成功,errno绝不会被重置为0
perror()会打印出其msg参数所指向的字符串,紧跟一条与当前errno值对应的消息
-
#include <stdio.h>
-
void perror(const char *msg);
strerror()会针对其errnum当中指定的错误号,返回相应的错误字符串
-
#include <string.h>
-
char *strerror(int errnum)
在POSIX线程API中,将errno重新定义为一个函数(以宏的形式),该函数会返回一个指向线程专用存储区域(thread specific)的指针
标准系统数据类型
其命名均以_t结尾,其中的许多都声明于头文件,应用程序采用这些类型定义来声明其使用的变量,才能保证可移植性。如遇到printf()等函数时,需要转换为不同实现当中的最大类型之后,再打印,如:
-
printf("My PID is %ld\n", (long)mypid)
阅读(1479) | 评论(0) | 转发(0) |