《Linux 高级程序设计(第三版)》——1.2 Linux开发初步

简介:

本节书摘来自异步社区《Linux 高级程序设计(第三版)》一书中的第1章,第1.2节,作者:杨宗德 , 吕光宏 , 刘雍著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.2 Linux开发初步

Linux 高级程序设计(第三版)
1.2.1 Linux下C程序标准
在Linux操作系统下进行C程序开发的标准主要有两个:ANSI C标准和POSIX标准。

ANSI C标准是ANSI(美国国家标准局)于1989年制定的C语言标准,后来被ISO(国际标准化组织)接受为标准,因此也称为ISO C。

POSIX标准是最初由IEEE开发的标准族,部分已经被ISO接受为国际标准。

1.ANSI C
ANSI C的目标是为各种操作系统上的C程序提供可移植性保证(例如Linux与Windows之间),而不仅仅限于类UNIX系统。该标准不仅定义了C编程语言的语法和语义,而且还定义了一个标准库。ISO C标准定义的头文件如表1-1所示。
screenshot
screenshot

2.POSIX标准
POSIX.1和POSIX.2分别定义了兼容操作系统的C语言系统接口以及工具标准。Posix是类UNIX系统都遵循的标准,例如Ubuntu下和RedHat下没有代码不需要移植可直接编译后执行,而在Linux下基于Posix标准完成的代码就无法在Windows下直接编译并执行。表1-2所示为26项POSIX标准定义的头文件,表1-3所示为26项POSIX标准定义的XSI扩展头文件,表1-4所示为8项POSIX标准定义的可选头文件。
screenshot
screenshot
screenshot
screenshot
screenshot

1.2.2 库函数和系统调用
1.系统调用函数和库函数
库函数用以完成常见的特定功能,通常由某一个组织制作发布,并形成一定的标准,可以应用于不同的平台而不需要做任何修改即具有极好的移植性。例如,C函数库能够被绝大多数C编译器支持。

系统调用函数一般与操作系统相关,不同的操作系统所使用的系统调用可能不同。一般来说,如果两个操作系统差异很大,系统调用函数的可移植性就不高。例如Windows采用了系统调用的应用程序不能直接在Linux下编译运行。系统调用函数很多情况下需要访问系统特殊资源,在Linux下,系统调用采用软中断来实现,使用系统调用时,该程序的状态将从用户态切换到内核态。图1-1所示为Linux函数库调用和系统调用示意图。

screenshot

库函数在实现最终都需要使用系统调用,但它封装了系统调用的部分操作,用户不必关心它使用了哪些系统调用。另外,做上层应用程序开发时也没有必要深入研究系统调用函数的具体实现过程。

2.glibc函数库
众所周知,C语言并没有为常见的操作,例如输入/输出、内存管理等提供内置的支持。这些功能一般由标准的函数库来提供。GNU的C函数库glibc是Linux最重要的函数库,它定义了ISO C标准指定的所有库函数,以及由POSIX或其他UNIX操作系统变种指定的附加特色,还包括与GNU系统相关的扩展。目前,Linux系统大多使用glibc 2.3以上的版本。glibc基于如下标准。

(1)ISO C。C编程语言的国际标准,即ANSI C。

(2)POSIX。GNU C函数库实现了ISO/IEC 9945-1:1996(POSIX系统应用程序编程接口,即POSIX.1)指定的所有函数。该标准是对ISO C的扩展,包括文件系统接口原语、设备相关的终端控制函数以及进程控制函数。同时,GUN C函数库还支持部分由ISO/IEC 9945-2:1993(POSIX Shell和工具标准,即POSIX.2)指定的函数,其中包括用于处理正则表达式和模式匹配的函数。

(3)Berkeley UNIX(BSD和SunOS)。GNU C函数库定义了某些UNIX版本中尚未标准化的函数,尤其是4.2 BSD,4.3 BSD,4.4 BSD UNIX系统(即Berkeley UNIX)以及SunOS(流行的4.2 BSD变种,其中包含某些UNIX System V的功能)。BSD函数包括符号连接、select函数、BSD号处理函数以及套接字等。

(4) SVID(System V的接口描述)。GNU C函数库定义了大多数由SVID指定而未被ISO C和POSIX标准指定的函数。来自System V的支持函数包括进程间通信和共享内存、hsearch和drand48函数族、fmtmsg以及一些数学函数。

(5)XPG(X/Open可移植性指南)。GNU C函数库遵循X/Open可移植性指南(Issue 4.2)以及所有的XSI(X/Open系统接口)兼容系统的扩展,同时也遵循所有的X/Open UNIX扩展。

3.系统调用
系统调用是操作系统提供给外部程序的接口。在C语言中,操作系统的系统调用一般通过函数调用的形式完成。因为这些函数封装了系统调用的细节,将系统调用的入口、参数以及返回值用C语言的函数调用过程实现。在Linux系统中,系统调用函数定义在glibc中。系统调用需要注意以下几点。

(1)系统调用函数通常在成功时返回0值,不成功时返回非零值。如果要检查失败原因,则要判断全局变量errno的值,errno中包含错误代码。

(2)许多系统调用的返回数据通常通过引用参数传递。这时,需要在函数参数中传递缓冲区地址,而返回的数据就保存在该缓冲区中。

(3)不能认为系统调用函数比其他函数的执行效率高。因为系统调用是一个非常耗时的过程。

1.2.3 在线文档介绍
Linux是免费的自由软件操作系统,大量的应用程序都是由自由组织和个人编写,没有特别大型的公司维护。因此,在程序中出现的大量问题都需要程序开发人员自己解决。一般的解决方案是查看该程序的帮助文件,因为Linux开发人员在发布其个人程序时都添加了详细的帮助文件。在Linux系统下,常用的在线帮助文件有man、info以及HOW-TO等。最常用的是man手册。

1.man手册
man即manual,是UNIX系统手册的电子版本。根据习惯,UNIX系统手册通常分为不同的部分(或小节,即section),每个小节阐述不同的系统内容。目前的小节划分如下。

man 1:命令,例如ls。可以查看shell终端下命令使用介绍。
man 2:系统调用。可以查看内核系统调用函数的描述,以及参数和返回值情况。
man 3:函数库调用。可以查看普通函数库中的函数。
man 4:特殊文件。可以查看/dev目录中的特殊文件。
man 5:文件格式和约定。可以查看/etc/passwd等文件的格式,例如man /etc/passwd。
man 6:游戏。
man 7:杂项和约定。标准文件系统布局、手册页结构等杂项内容。
man 8:系统管理命令。只有管理员使用的命令。
man 9:内核例程。非标准的手册小节,便于Linux内核的开发而包含其他手册小节。
例如,常用命令行:

man 2 open      //查看open函数帮助
man 7 man      //在第7部分查看man功能

2.info手册
Linux中的大多数软件开发工具都来自自由软件基金会的GNU项目,这些工具软件的在线文档都以info文件的形式存在。info程序是GNU的超文本帮助系统。info文档一般保存在/usr/info目录下,使用info命令可以查看info文档。要运行“info”,可以在shell提示符后输入“info”,也可以在GNU的emacs中键入“Esc-x info”。

info帮助系统的初始屏幕显示为一个主题目录,可以将光标移动到带有“*”的主题菜单上面,然后按回车键进入该主题,也可以键入“m主题菜单的名称”进入该主题。例如,你可以键入“m”,然后再键入“gcc”进入gcc主题中。如果要在主题之间跳转,则必须记住如下几个命令键。

n:跳转到该节点的下一个节点。
p:跳转到该节点的上一个节点。
m:指定菜单名。
f:进入交叉引用主题。
l:进入该窗口中的最后一个节点。
TAB:跳转到该窗口的下一个超文本链接。
RET:进入光标处的超文本链接。
u:转到上一级主题。
d:回到info的初始节点目录。
h:跳出info教程。
q:退出info。
3.HOW-TO
可供用户参考的联机文档的另一种形式是HOWTO文件,这些文件位于系统的/usr/doc/HOWTO目录下。HOWTO文件的文件名都有-HOWTO后缀,并且都是文本文件。每一个HOWTO文件包含Linux某一方面的信息,例如支持硬件或如何建立引导盘。要想查看这些文件,进入/usr/doc/HOWTO目录,使用more命令,具体形式如下:

$ cd /usr/doc/HOWTO;more topic-name-HOWTO //切换到该目录
另外,还有其他格式的HOWTO文档,例如HTML和PS等,保存在/usr/doc/HOWTO/ other-formats下。

4.其他
Linux的内核文档一般包含在内核源代码目录/usr/src/'uname –r'/Documentation/usr/doc中,该目录下包含有大量与特定软件或函数库相关的说明性文档。

1.2.4 获取错误信息
调用库函数或系统调用函数后,如果执行成功将返回0或者正确值;如果执行失败,返回 − 1,并把系统全局变量errno赋值,以指示具体的错误情况。该变量在文件errno.h头文件中被声明,具体如下所示:

#ifndef errno
extern int errno;
#endif

所有的错误代码都在errno.h文件中定义。以下是/usr/include/asm/errno.h文件部分内容:

come from /usr/include/asm/errno.h
#ifndef _I386_ERRNO_H
#define _I386_ERRNO_H
#define EPERM    1 /* Operation not permitted */ //没有操作权限
#define ENOENT    2 /* No such file or directory */ //文件和目录不存在
#define ESRCH   3 /* No such process */   //没有此程序
#define EINTR    4 /* Interrupted system call */ //系统调用中断
#define EIO     5 /* I/O error */    //I/O错误
……

为了打印出具体的errno值所对应的错误提示信息,一般使用perror函数。此函数声明如下:

//come from /usr/include/stdio.h 
//Print a message describing the meaning of the value of errno. //打印错误值的具体信息描述
extern void perror (__const char *__s);      //perror函数声明

另外,Linux系统还提供了以下错误处理函数:

#include <string.h>          //string.h头文件中
    char *strerror(int errnum);        //strerror函数声明
#include <errno.h>          //errno.h头文件中
    extern char *sys_errlist[ ];        //sys_errlist函数声明
    extern int sys_nerr;          //sys_nerr函数声明

如果在应用程序中使用系统调用出错后使用perror(),可将错误相关的消息写入到标准错误输出,描述调用系统函数或库函数期间遇到的最后一个错误。perror()函数首先输出参数字符串s,后接冒号、空格、消息和换行符。为发挥它最大的作用,参数字符串应包括导致错误的程序的名称。如下示例所示:

if (chmod("test02", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) 
{
     perror("stat");
    exit(EXIT_FAILURE);
}

如果上例的chmod()函数调用失败,将打印“stat: 具体的errno message”错误信息。

错误编号取自符号errno,出错时将设置此符号,但执行无错误调用后不会清除此符号。消息的内容与将errno用作参数的strerror()函数返回的内容相同。如果给定了一个NULL字符串,则perror()函数只输出消息和换行符。

相关文章
|
4月前
|
存储 网络协议 Ubuntu
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
248 2
|
13天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
54 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
存储 Linux 开发工具
如何进行Linux内核开发【ChatGPT】
如何进行Linux内核开发【ChatGPT】
|
3月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
41 6
|
3月前
|
消息中间件 算法 Unix
Linux设备驱动开发详解1
Linux设备驱动开发详解
46 5
|
3月前
|
编解码 安全 Linux
基于arm64架构国产操作系统|Linux下的RTMP|RTSP低延时直播播放器开发探究
这段内容讲述了国产操作系统背景下,大牛直播SDK针对国产操作系统与Linux平台发布的RTMP/RTSP直播播放SDK。此SDK支持arm64架构,基于X协议输出视频,采用PulseAudio和Alsa Lib处理音频,具备实时静音、快照、缓冲时间设定等功能,并支持H.265编码格式。此外,提供了示例代码展示如何实现多实例播放器的创建与管理,包括窗口布局调整、事件监听、视频分辨率变化和实时快照回调等关键功能。这一技术实现有助于提高直播服务的稳定性和响应速度,适应国产操作系统在各行业中的应用需求。
|
4月前
|
Web App开发 缓存 Linux
FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
《FFmpeg开发实战》书中第10章提及轻量级流媒体服务器MediaMTX,适合测试RTSP/RTMP协议,但不适合生产环境。推荐使用SRS或ZLMediaKit,其中SRS是国产开源实时视频服务器,支持多种流媒体协议。本文简述在华为欧拉系统上编译安装SRS和FFmpeg的步骤,包括安装依赖、下载源码、配置、编译以及启动SRS服务。此外,还展示了如何通过FFmpeg进行RTMP推流,并使用VLC播放器测试拉流。更多FFmpeg开发内容可参考相关书籍。
94 2
FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
|
4月前
|
Linux
FFmpeg开发笔记(三十四)Linux环境给FFmpeg集成libsrt和librist
《FFmpeg开发实战》书中介绍了直播的RTSP和RTMP协议,以及新协议SRT和RIST。SRT是安全可靠传输协议,RIST是可靠的互联网流传输协议,两者于2017年发布。腾讯视频云采用SRT改善推流卡顿。以下是Linux环境下为FFmpeg集成libsrt和librist的步骤:下载安装源码,配置、编译和安装。要启用这些库,需重新配置FFmpeg,添加相关选项,然后编译和安装。成功后,通过`ffmpeg -version`检查版本信息以确认启用SRT和RIST支持。详细过程可参考书中相应章节。
77 1
FFmpeg开发笔记(三十四)Linux环境给FFmpeg集成libsrt和librist
|
4月前
|
弹性计算 运维 自然语言处理
阿里云OS Copilot测评:重塑Linux运维与开发体验的智能革命
阿里云OS Copilot巧妙地将大语言模型的自然语言处理能力与操作系统团队的深厚经验相结合,支持自然语言问答、辅助命令执行等功能,为Linux用户带来了前所未有的智能运维与开发体验。
|
5月前
|
编解码 Linux
FFmpeg开发笔记(二十八)Linux环境给FFmpeg集成libxvid
XviD是开源的MPEG-4视频编解码器,曾与DivX一起用于早期MP4视频编码,但现在已被H.264取代。要集成XviD到Linux上的FFmpeg,首先下载源码,解压后配置并编译安装libxvid。接着,在FFmpeg源码目录中,重新配置FFmpeg以启用libxvid,然后编译并安装。成功后,通过`ffmpeg -version`检查是否启用libxvid。详细步骤包括下载、解压libxvid,使用`configure`和`make`命令安装,以及更新FFmpeg配置并安装。
77 2
FFmpeg开发笔记(二十八)Linux环境给FFmpeg集成libxvid