当前课程知识点:基于Linux的C++ > 第十二讲 Linux系统编程基础 > 12.2 程序执行环境(一) > LinuxCPP1202
我们首先来看程序执行环境
在程序执行环境这一节
主要包括七个主题
一个是参数列表 第二个是环境变量
第三个是程序退出码
第四个是程序调用的错误处理
第五个是资源管理
最后两个是系统日志和用户信息
我们首先来看参数列表
对 Linux 操作系统来讲
它的命令行是遵照一定的规范的
首先在书写命令行的时候
你可以提供一系列的参数
这些参数是以短参数或长参数的格式来提供的
这些参数是以短参数或长参数的格式来提供的
这两种格式其实都可以
如果是一个短参数的话
它就是一个单横来开头
后面跟着一个单一的字符
比如讲 “ls –h” 它这就是一个短参数
如果是长参数的话的呢
那么就是一个双横来开头
后面跟着就是一个字符串
它就不是一个单一的字符了
比如讲 “ls --help”
就是看 ls 的帮助 也就这个意思
这是 Linux 的命令行规范
当我们在程序中想访问这个程序的参数列表的时候
当我们在程序中想访问这个程序的参数列表的时候
它有一个一定的方案
首先 main() 函数的那个参数
我们此前从来都没用过
事实上我们也没怎么写过
它其实是可以带两个参数的
一个参数呢叫 argc 一个参数叫 argv
这两个参数其实就表达了 Linux 命令行里
这两个参数其实就表达了 Linux 命令行里
后面带的那些附加的参数
我们在程序中就可以通过分析 argc、argv
这两个参数来获取 Linux 命令行里
提供的那些参数的列表
按照这个方式处理它就可以了
我们看这样一个例子
编写程序 输出命令行参数
main() 函数带双参数 argc、argv
argc 是一个整型参数
它表达的是什么呢
它表达是 main() 函数的参数有几个
这是最重要的一个参数
这个参数的计数是包括这个命令本身的
所以命令本身是它的第 0 个参数
接下来才是它真正地附带的那个参数
从第 1 号位开始
这些参数存在什么地方呢
这些参数存在 argv 里
argv 是一个字符串数组
首先它是一个数组
其次呢 它的每个元素都是一个字符串
这个数组的排布就是一个字符串
接着一个字符串 接着一个字符串
每一个字符串都是以 “\0” 结尾的
在所有的这些字符串都结尾之后
再用一个 “\0” 来结尾
表达它的全部字符串的结束
它实际上是按照这样的一个模式
来存储我们的 argv 的
那么在我们的 main() 函数里
我们就可以根据 argc 的值来决定
它到底带没带参数
当 argc 大于 1 的时候
说明它就有参数了
因为 argc 等于 1 的话那实际上
就意味着只有命令本身
它后面没有其它参数了
那么我们怎么在程序中
分析我们的参数列表呢
Linux 操作系统为我们定义了一个结构体
这个结构体的名字叫 option
我们使用这个结构体 option 就可以分析 Linux 命令
我们使用这个结构体 option 就可以分析 Linux 命令
在程序执行过程中所提供的那些参数
这个结构体定义在 “getopt.h” 这个头文件里
它包括了四个字段
第一个字段是 name 表示选项的长名称
第二个字段是 has_arg
表示它是不是具有的附加的参数
如果是 0 表示它没有附加参数
1 就表示有附加参数
2 就表示有可选的附加参数
就是也许有 也许没有
三 是一个指向整数的指针 flag
它用来保存 value 的值
有时候我们需要用
有时候我们不需要用它
第四个是选项的短名称 val
用来存储你在 Linux 命令行
输入的这个参数所对应的短名称
因为你可能输入的是长选项
那么这个地方保存的就是那个选项的短名称
那么这个地方保存的就是那个选项的短名称
长名称是在第一个字段保存的
分析 Linux 命令行参数列表的那个函数
名字叫 getopt_long()
这个函数比较长 参数比较多
argc、argv 是两个分析命令行参数的主要的参数
argc、argv 是两个分析命令行参数的主要的参数
argc 和 argv 是 main() 函数
传过来那两个参数
接下来那两个参数保存就是选项的信息
一个是短选项 一个是长选项
对于短选项来讲它是一个字符串
对于长选项来讲呢
它是一个指向 option 结构体的指针
第五个 用来表达的就是它那个长选项
第五个 用来表达的就是它那个长选项
它事实上在那个选项数组里边的对应的索引
它事实上在那个选项数组里边的对应的索引
所以这个函数的返回值
当你调用 getopt_long()
去分析 Linux 参数列表的时候
每一次它会分析出 Linux 命令行里边的一个参数
每一次它会分析出 Linux 命令行里边的一个参数
如果这个参数是合法有效的
它就会返回那个参数所对应的
短选项那个字符
如果那个参数不存在 它就会返回 -1
如果在参数列表中提供的是长选项
那么它的第五个参数就会输出
那个长选项在长选项数组里边的索引
就是它下标是几
这样的话 你就能够查找到它对应的短选项的名称和其它附加信息
这样的话 你就能够查找到它对应的短选项的名称和其它附加信息
就是这个意思
在实际编程的时候
我们需要使用循环来处理所有的命令行参数
我们需要使用循环来处理所有的命令行参数
如果在处理的过程中遇到错误选项
如果在处理的过程中遇到错误选项
那么就应该输出错误的信息
并且终止程序的运行
当你处理附加参数的时候
可以使用全局变量 optarg
来获取它那个附加参数的基地址
在完成所有的处理之后
全局变量 optind
存储首个非可选参数的索引
你比如讲 我们写这样一个程序
接受三个选项 执行正确的处理
第一个选项是 “-h”/“--help”
显示程序的帮助信息然后退出
第二个选项是 “-o filename”
或者 “--output_filename”
“-o” 选项
它就会带一个附加的参数 filename 文件名
“-v” 和 “--verbose” 用来输出复杂的信息
“-v” 和 “--verbose” 用来输出复杂的信息
缺省情况下边
这些复杂信息我们是不输出的
如果你设定了这个开关
那么在程序运行过程中
就会输出复杂的信息
这样能帮助你调试你的程序代码
我们看程序代码
在这个程序代码里边
我们定义一个全局量 program_name
来存储我们这个程序的实际的名字
然后我们定义一个函数 OutputInfo() 来输出信息
然后我们定义一个函数 OutputInfo() 来输出信息
因为这个输出的信息
有的时候是向标准输出流
有的时候是向标准错误流里输出
所以我们提供一个输出流的参数 os
ostream 的一个引用
然后提供一个退出码
在这个函数的内部简单地将整个程序的使用方法罗列一下
在这个函数的内部简单地将整个程序的使用方法罗列一下
输出 就 OK 了
关键是我们的主函数
在主函数里
我需要定义一个短选项的字符串
这个字符串不能变 全是常数
所以是 const char * const short_opts
这个短选项字符串有一个特别定义的规格
这个短选项字符串有一个特别定义的规格
字符串的内容是所有短选项的简单拼接
字符串的内容是所有短选项的简单拼接
你必须按照那个选项顺序拼接
跟长选项必须完全对应的
一个选项一个字符
如果这个选项有一个附加参数
后面就要带 “:”
因为我们这里边提供了三个附加参数
顺序是 “hov”
所以我们写的这个短选项字符串就是 “ho:v”
这就是我们短选项字符串
它对应的长选项数组
你也必须按照这个格式来
"help", 0, NULL,'h' 这是第一个选项
"output",1, NULL,'o' 这是第二个选项
我们前面不解释了吗
第二个参数表示它有没有附加参数
0 表示没有
1 表示它有一个附加参数
就按照这个模式写就行了
写完这三个选项之后
记得在最后封装一个空选项
NULL, 0, NULL, 0
用来表达这个长选项数组结束了
必须按照这个格式来定义
然后我们首先定义一个 output_filename 输出文件名
然后我们首先定义一个 output_filename 输出文件名
把它设成 NULL 初始化成 NULL
然后我们把 verbose 初始化成 0
然后我们把 program_name 初始化成 argv[0]
接下来就我们需要调用 getopt_long()
来处理它的每一个参数
getopt_long() 这个函数在处理参数的时候
它一次只能处理一个
你把 argc、argv、short_opts、long_opts、NULL
这五个参数全传进去以后
它返回的呢
就是对应那个 option 那个选项
那个选项处理的是第一个
然后我们根据它的选项返回值
看它是不是 -1
如果是 -1 就说明处理完了嘛
如果不是我们就要一个接着一个地去处理
用一个 switch 来去处理它
如果它是 “h” 我们就输出它的用法
就是用户想看这个程序怎么用
你就输出它的用法
如果是 “o” 那我们就把
output_filename 设成 optarg
刚才不谈到过了吗
带着一个附加参数的一个选项
那么它的那个附加参数怎么获得呢
就是通过全局量 optarg
就 optarg 选项参数
就这个意思 用它来获得
它已经给你保存好了
你拿过来直接用就 OK 了
然后 break
“v” 我们就把 verbose 设成 1 break
“?” 说明出错了
发现了一个无效的参数
我们就向标准错误流里输出信息
如果是 “-1”
表示处理完毕了
连 “-1” 都不是
那就程序出现了未知错误
我们就 abort() 结束了
这一个参数处理完毕了
那我们接下来就要处理第二个参数
所以继续调用 getopt_long()
处理它的下一个参数 循环
按照这个模式就能够将 Linux 命令行的全部的参数都处理完
按照这个模式就能够将 Linux 命令行的全部的参数都处理完
-1.1 提纲
-1.2 程序设计的基本概念
-1.3 简单C/C++程序介绍
-1.4 程序设计的基本流程
-1.5 基本语法元素
-1.6 程序设计风格
-1.7 编程实践
-第一讲 C/C++基本语法元素--编程实践提交入口
-2.1 提纲
-2.2 结构化程序设计基础
-2.3 布尔数据
-2.4 分支结构
-2.5 break语句
-2.6 循环结构
-2.7 编程实践
-第二讲 程序控制结构--编程实践提交入口
-3.1 提纲
-3.2 函数声明、调用与定义
-3.3 函数调用栈框架
-3.4 编程实践
-第三讲 函数--编程实践提交入口
-4.1 提纲
-4.2 算法概念与特征
-4.3 算法描述
-4.4 算法设计与实现
-4.5 递归算法(一)
-4.6 递归算法(二)
-4.7 容错与计算复杂度
-4.8 编程实践
-第四讲 算法--编程实践提交入口
-5.1 提纲
-5.2 库与接口
-5.3 随机数库(一)
-5.4 随机数库(二)
-5.5 作用域与生存期
-5.6 典型软件开发流程(一)
-5.7 典型软件开发流程(二)
-5.8 编程实践
-第五讲 程序组织与开发方法--编程实践提交入口
-6.1 提纲
-6.2 字符
-6.3 数组(一)
-6.4 数组(二)
-6.5 结构体
-6.6 编程实践
-第六讲 复合数据类型--编程实践提交入口
-7.1 提纲
-7.2 指针基本概念
-7.3 指针与函数
-7.4 指针与复合数据类型(一)
-7.5 指针与复合数据类型(二)
-7.6 字符串
-7.7 动态存储管理(一)
-7.8 动态存储管理(二)
-7.9 引用
-7.10 编程实践
-第七讲 指针与引用--编程实践提交入口
-8.1 提纲
-8.2 数据抽象(一)
-8.3 数据抽象(二)
-8.4 链表(一)
-8.5 链表(二)
-8.6 链表(三)
-8.7 链表(四)
-8.8 函数指针(一)
-8.9 函数指针(二)
-8.10 抽象链表(一)
-8.11 抽象链表(二)
-8.12 编程实践
-第八讲 链表与程序抽象--编程实践提交入口
-9.1 提纲
-9.2 程序抽象与面向对象
-9.3 类类型
-9.4 对象(一)
-9.5 对象(二)
-9.6 类与对象的成员(一)
-9.7 类与对象的成员(二)
-9.8 类与对象的成员(三)
-9.9 继承(一)
-9.10 继承(二)
-9.11 继承(三)
-9.12 多态(一)
-9.13 多态(二)
-9.14 编程实践
-第九讲 类与对象--编程实践提交入口
-10.1 提纲
-10.2 四则运算符重载(一)
-10.3 四则运算符重载(二)
-10.4 关系与下标操作符重载
-10.5 赋值操作符重载(一)
-10.6 赋值操作符重载(二)
-10.7 赋值操作符重载(三)
-10.8 赋值操作符重载(四)
-10.9 赋值操作符重载(五)
-10.10 流操作符重载(一)
-10.11 流操作符重载(二)
-10.12 流操作符重载(三)
-10.13 操作符重载总结
-10.14 编程实践
-第十讲 操作符重载--编程实践提交入口
-11.1 提纲
-11.2 泛型编程概览
-11.3 异常处理机制(一)
-11.4 异常处理机制(二)
-11.5 运行期型式信息(一)
-11.6 运行期型式信息(二)
-11.7 模板与型式参数化
-11.8 题外话:术语翻译
-11.9 泛型编程实践(一)
-11.10 泛型编程实践(二)
-11.11 泛型编程实践(三)
-11.12 泛型编程实践(四)
-11.13 泛型编程实践(五)
-11.14 泛型编程实践(六)
-11.15 泛型编程实践(七)
-11.16 泛型编程实践(八)
-11.17 泛型编程实践(九)
-11.18 泛型编程实践(十)
-11.19 编程实践
-第十一讲 泛型编程--编程实践提交入口
-12.1 提纲
-12.2 程序执行环境(一)
-12.3 程序执行环境(二)
-12.4 程序执行环境(三)
-12.5 程序执行环境(四)
-12.6 输入输出(一)
-12.7 输入输出(二)
-12.8 文件系统
-12.9 设备
-12.10 库(一)
-12.11 库(二)
-12.12 makefile文件(一)
-12.13 makefile文件(二)
-12.14 makefile文件(三)
-12.15 编程实践
-第十二讲 Linux系统编程基础--编程实践提交入口
-13.01 提纲
-13.02 进程基本概念
-13.03 信号
-13.04 进程管理(一)
-13.05 进程管理(二)
-13.06 进程管理(三)
-13.07 进程间通信(一)
-13.08 进程间通信(二)
-13.09 进程间通信(三)
-13.10 进程间通信(四)
-13.11 进程池
-13.12 编程实践
-第十三讲 进程编程--编程实践提交入口
-14.1 提纲
-14.2 线程基本概念
-14.3 线程管理(一)
-14.4 线程管理(二)
-14.5 线程管理(三)
-14.6 线程管理(四)
-14.7 线程同步机制(一)
-14.8 线程同步机制(二)
-14.9 C++11线程库(一)
-14.10 C++11线程库(二)
-14.11 C++11线程库(三)
-14.12 C++11线程库(四)
-14.13 C++11线程库(五)
-14.14 编程实践
-第十四讲 线程编程--编程实践提交入口
-15.1 提纲
-15.2 Internet网络协议
-15.3 套接字(一)
-15.4 套接字(二)
-15.5 编程实践
-第十五讲 网络编程--编程实践提交入口