《Linux程序设计》学习笔记04——Linux环境


Linux 编写程序时,必须考虑到程序将在一个多任务环境中运行。这意味着在同一时间会有多个程序运行,它们共享内存、磁盘空间和 CPU 周期等机器资源。甚至同一程序也会有多个实例同时运行。最重要的是,这些程序能够互不干扰,了解他们的环境,并且能正确运行以避免冲突——例如试图与其他程序同时写同一个文件。

 

程序参数

无论操作系统何时启动新程序,参数 argc argv 都被设置并传递给 main 。这些参数通常由其他程序提供,这个程序一般是 shell ,它请求操作系统启动该新程序。

注意 Linux shell 一般会在设置 argc argv 之前对文件名参数进行通配符扩展,而 MS-DOS shell 则期望程序接受带通配符的参数并执行它们自己的通配符扩展。

命令行参数 在向程序传递信息方面是很有用的。许多工具程序都是有命令行参数来改变程序的行为或设置选项。这些参数大多以短横线( - )开头;不带后续参数的选项还可在一个短横线后归并到一起。

当需要在自己的程序中处理这些命令行参数时,我们需要自己对这些参数解析从而判断出有效的参数。当参数个数很多时,这一过程将是非常繁琐的。实际上, X/Open 规范定义了命令行选项的标准用法,同时定义了在 C 语言程序中提供命令行开关的标准编程接口: getopt 函数。

getopt 函数 将传递给 main 程序的 argc argv 作为参数,同时接受一个选项指定字符串 optstring ,该字符串高速 getopt 哪些选项可用,以及每个选项是否有关联值。程序将循环调用 getopt 对选项参数进行处理,直到 getopt 返回 -1 时处理完毕。关于 getopt 的详细信息请查阅 man 手册。

我们在实际使用中可能会选择长参数,它以双短横线( -- )表示。 GNU C 库包含了 getopt 的另一个版本,称为 getopt_long ,它能同时接受短参数和长参数。 getopt_long 函数 getopt 函数多了两个参数,一个被定义为 option 结构(它指定了函数可以接受的长参数和函数对应返回的值),另一个通常被置 NULL

提示 :在使用 getopt_long 函数时,除了要包含头文件 getopt.h 外,还需要把常量 _GNU_SOURCE 一同包含进来。

 

无参数和 void 参数

在定义自己的程序时,当不需要传递参数时我们可能置参数列表为空或者填入 void 。那么这两种方式相同么?考虑下面两个函数

void foo1();

void foo2(void);

当我们使用 foo1(1,2) 调用 foo1 函数时编译器将不报任何错误,同时可以正常运行;它的执行结果与调用 foo1() 的结果一致。然而,当我们使用 foo2(1,2) 调用 foo2 函数时编译器将报错。因此,无参数和 void 参数使得函数显现出两种不同的行为。

实际上, void 参数指定函数在调用时不能有任何参数;而无参数则没有对参数的传递做任何的规范,也就是说,你可以传递任何类型的任意个数的参数。

 

环境变量

环境变量是一把双刃剑,使用它的时候要小心!与命令行选项相比,它们对用户来说更加“隐蔽”,这样就使得调试变得更加困难。从某种意义上来说,环境变量就像全局变量一样,它们会改变程序的行为,产生不可预期的结果。

对于环境环境变量的读写操作可以有两种方式,在《 Unix 环境下 C 语言编程及项目实践》的 读书笔记 4 中有详细的介绍。

 

时间和日期

通常能确定时间和日期对一个程序来说是非常有用的。

我们可以使用 time 函数获取一个 time_t 类型的时间值,该值是从格林威治时间到当前时间点的秒数。函数 localtime 将一个 time_t 类型的时间值转换为 tm 结构,通过该结构可以清晰得了解当前的年、月、日、时、分等。函数 mktime 的功能则相反,它将一个 tm 结构的时间值转换为 time_t 类型。上面的几个函数在《精通 Unix C 语言编程及项目实践》的 读书笔记 5 中有详细的介绍。

为了得到更“友好”的时间和日期表示,像 date 命令输出的那样,我们可以使用 asctime 函数和 ctime 函数。实际上,为了对时间和日期字符串的格式有更多的控制, Linux 和现代的类 UNIX 系统提供了 strftime strptime 函数。它很像是一个针对时间和日期的 sprintf sscanf 函数,具体的信息请查看 man 手册。

注意 :编译包含了 strptime 函数的程序时,需要在包含 time.h 头文件的语句之前包含 _XOPEN_SOURCE 宏定义。

提示 :我们在程序中经常使用 sleep 函数来完成指定时间的睡眠。实际上, sleep 函数只能指定秒级的时间,如果要精确到微妙级 (10 -6 s) 可以使用 usleep 函数 。除此之外,还有一个 timeval 结构 可以完成微妙级的操作。

 

临时文件

很多情况下,程序会利用一些文件形式的临时存储手段。这些临时文件可能保存着一个计算的中间结果,也可能是关键操作的文件备份。

临时文件的用法很常见,但必须确保应用程序为临时文件选取的文件名是唯一的。 GNU C 提供了两个函数 tmpname tmpfile 来创建临时文件。详细情况请参考 man 手册。

提示 :当需要创建临时文件且需要对其进行读写时,请优先考虑使用 tmpfile 函数。该函数同时创建和打开临时文件,这样就避免了使用 tmpnam 函数时可能有另一个程序用同样的名字打开文件的风险。

 

用户及主机信息

程序能够通过检查环境变量和读取系统时钟来在很大程度上了解它所处的运行环境。除此之外,程序还可以发现它的使用者的相关信息。

函数 getuid getlogin 分别获取程序关联的 UID 和与该关联 ID 相应的登录名。

实际上,系统文件 /etc/passwd 包含了一个用户账户数据库。要获取某个用户的信息, UNIX 系统并不推荐直接对该系统文件读写,它定义了一组函数来提供一个标准二又有效地获取用户信息的编程接口 getpwuid getpwnam 。它们均返回一个指向与某个用户对应的 passwd 结构指针。

提示 :你可以对程序进行设置,让它们的运行看上去好像是由另一个用户启动的。当一个程序的 SUID 权限被置位时,它的运行就好像是由该可执行文件的属主启动的。一个典型的例子是 su 命令。

UNIX 环境下,可以使用 uname 系统调用来获取主机信息。它将主机信息写入一个 utsname 结构。详细细节请查阅 man 手册。

 

日志

许多应用程序需要记录它们的活动。系统程序经常需要向控制台或日志文件写消息。这些消息能指示错误、警告或是与系统状态有关的一般信息。

提示 :当程序短小时我们经常使用 gdb 工具来调试;但当程序比较庞大时,一个有效地调试手段就是使用日志功能,在日志中搜索出错信息。

UNIX 规范为所有程序提供了一个接口,通过 syslog 函数来产生日志信息。这些信息往往被记录在日志文件 /var/log/message 中,部分调试信息可能记录在 /var/log/debug 中。

通过 syslog 函数向系统的日志文件发送的每条日志信息都有一个优先级。而且不同程序写入的日志信息并不能明显地区分开来。实际上, UNIX 提供了几个函数来改变日志记录行为: openlog closelog setlogmask 函数。有效地使用这三个函数可以在日志文件中与其他程序写入的日志区分开。关于详细信息请查阅 man 手册。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值