文件I/O与系统编程

文件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相当

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值