文件IO与系统编程
本文是作者阅读TLPI(The Linux Programer Interface的总结),为了突出重点,避免一刀砍,我不会过多的去介绍基本的概念和用法,我重点会去介绍原理和细节。因此对于本文的读者,至少要求读过APUE,或者是实际有写过相关代码的程序员,因为知识有点零散,所以我会尽可能以FAQ的形式呈现给读者。
修订历史:
2016/12/05 对于符号链接解引用的判断,补充磁盘空间分配一节
2017/1/14 新增对O_EXCL的解释,对open打开目录的行为进行了补充,新增对于文件空洞的判断。
2017/5/24 新增open打开目录的示例
系统编程概览
如何确定glibc的版本?
可以分为下面两种方式:
第一种就是直接查看,先通过ldd来定位glibc的位置,然后通过直接运行glibc库就可以查看到其版本号了.
[root@localhost ~]# ldd /bin/ls
............
libc.so.6 => /lib64/libc.so.6 (0x00007f62209f3000)
.............
[root@localhost ~]# /lib64/libc.so.6
GNU C Library (GNU libc) stable release version 2.17, by Roland McGrath et al.
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.5 20150623 (Red Hat 4.8.5-4).
Compiled on a Linux 3.10.0 system on 2016-02-16.
Available extensions:
The C stubs add-on version 2.1.2.
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
RT using linux kernel aio
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.
如上图,可以看到glibc的版本是2.17,如果我们需要在我们的源代码中检测glibc的版本,因为我们的代码可能使用了一些高版本的glibc库函数。因此你可以使用下面这种方式第二种方式是通过__GLIBC__
和__GLIBC_MINOR__
这两个常量,是编译时常量,可以借助#ifdef
预处理指令来测试,也可以到运行时借助if来判断,因为这是两个常量,那么就会存在一个问题,如果在A系统上进行了编译,拿到B系统上运行,那么这两个常量就没有任何用处了,因为编译期就已经确定了其数值,除非在B系统上再次编译一次。为了应对这种可能,程序可以调用gnu_get_libc_version
这个函数来确定运行时所采用的glibc版本。代码如下:
#include <gnu/libc-version.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
int main()
{
//编译时获取glibc版本,A机器上编译,B机器上运行就会存在问题.需要使用运行时获取glibc版本
printf("major version:%d \t minor version:%d\n",__GLIBC__,__GLIBC_MINOR__);
//获取运行时的glibc版本
printf("glibc runtime version:%s\n",gnu_get_libc_version());
char buf[65535] ={
0};
// glibc特有的函数用来获取glibc版本,size_t confstr(int name, char *buf, size_t len);
assert(confstr(_CS_GNU_LIBC_VERSION,buf,sizeof(buf)) > 0);
printf("glibc version:%s\n",buf);
}
需要包含gnu/lib-version.h
这个头文件,__GLIBC__
是主版本号,__GLIBC_MINOR__
是次版本号,除了可以使用gnu_get_libc_version
函数外,还可以使用glibc特有的函数来获取glibc的版本号。
如何打印系统数据类型值?
对于C语言中的基本类型来说,很方便就可以通过printf来打印,但是linux系统通过typedef重新定义了很多系统数据类型,对于这些类型来说除非我们知道这个类型是对何种基本类型的typedef,否则很难正确的通过printf来打印,往往会导致打印的时候出现很多编译器的警告。例如下面这种情况。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
int main()
{
pid_t mypid;
mypid = getpid();
printf("mypid=%ld\n",mypid);
return 0;
}
gcc -Wall 1.c 进行编译,会出现下面的Warnning。
1.c: In function ‘main’:
1.c:10:2: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘pid_t’ [-Wformat=]
printf("mypid=%ld\n",mypid);
常见的应对策略是强制转换为long型,再使用%ld
。但是有一个例外在一些编译环境中off_t
的大小和long long
相当