UNIX环境高级编程(4):UNIX标准化及实现(2)

不确定的运行时限制:

如果某些限制值没有在<limits.h>中定义,则在编译时不能使用这些限制;而且即使对于运行时限制,如果它们的值是不确定的,那么它们也是未定义的。

如下的程序用来为路径名动态分配存储区(一般来说,很多程序在编译时就为其分配了存储区,而且不同的程序使用不同的幻数,例如256,512,1024或标准I/O常量BUFSIZ,但很少是正确的)。

/*
 * Copyright (C) [email protected]
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>

#define SUSV3 200112L
#define PATH_MAX_GUESS 1024

#ifdef PATH_MAX
	static int path_max = PATH_MAX;
#else
	static int path_max = 0;
#endif

static long posix_version = 0;

char *path_alloc(int *sizep);

char *
path_alloc(int *sizep)
{

	int size;
	char *ptr;

	if (posix_version == 0) {
		posix_version = sysconf(_SC_VERSION);
	}

	if (path_max == 0) {
		errno = 0;
		if ( (path_max = pathconf("/", _PC_PATH_MAX) < 0)) {
			if (errno == 0) {
				path_max = PATH_MAX_GUESS;
			} else {
				printf("pathconf errnor for _PC_PATH_MAX\n");
			}
		} else {
			path_max++;
		}
	}
	if (posix_version < SUSV3) {
		size = path_max + 1;
	} else {
		size = path_max;
	}

	if ( (ptr = malloc(size)) == NULL) {
		printf("malloc error\n");
	}

	if (sizep != NULL) {
		*sizep = size;
	}

	return ptr;
}

int
main()
{
	int size;
	char *ptr;

	ptr = path_alloc(&size);
	printf("PATH_MAX = %d\n", size);
	if (ptr != NULL) {
		free(ptr);
	}
	exit (0);
}

关于该程序有如下几点说明:

(1)pathconf函数返回的基于工作目录的相对路径名的最大长度,而工作目录是其第一个参数。所以使用根目录作为参数进行调用,并将得到的返回值加1,即可得到路径名的最大长度。

(2)SUS v3之前,对于PATH_MAX是否在路径名末尾已经包含了null字符这一点表述的不清楚,如果操作系统遵循先前的标准版本,则需在路径名分配的存储数量上加1。

(3)如果PATH_MAX是不确定的,我们只能猜一个值了。

最大打开文件数:

守护进程(daemon,是指在后台运行且不与终端相连接的一种进程,也称为精灵进程或后台进程)中一个常见的代码序列是关闭所有打开的文件。我们可以使用POSIX.1中的OPEN_MAX来确定最大打开文件数,以提高代码的可移植性。

下列程序获取最大的打开文件数,如果OPEN_MAX是未确定的,则只能猜测一个限制值。尽管这并不能保证在所有情况下都正确动作,但这却是我们所能选的最好的方法。

/*
 * Copyright (C) [email protected]
 */

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>

#ifdef OPEN_MAX
	static long openmax = OPEN_MAX;
#else
	static long openmax = 0;
#endif

#define OPEN_MAX_GUESS 256

long open_max(void);

long
open_max(void)
{
	if (openmax == 0) {
		errno = 0;
		if ( (openmax = sysconf(_SC_OPEN_MAX)) < 0) {
			if (errno == 0) {
				openmax = OPEN_MAX_GUESS;
			} else {
				printf("sysconf error for _SC_OPEN_MAX\n");
			}
		}
	}
	return openmax;
}

int
main()
{
	printf("oepnmax = %d\n", open_max());
	exit(0);
}

程序的运行结果如下:

这与ulimt -n的结果一致:

上述程序还有一个问题,由于Linux中可以调用ulimit命令随时更改可打开的最大文件数,而上述程序只在第一次调用open_max函数时调用sysconf函数,所以为了应对这种情况,应该修改上述程序,使得每次调用open_max时都会调用sysconf函数。

支持Single UNIX Specification 的XSI扩展的系统提供了getrlimit(2)函数,它可用来返回一个进程可以同时打开的最大描述符数。

选项:

如果我们要先写一些可移植的应用程序而这些程序与所得到支持的选项有关,那么就需要一种可移植的方法已决定是否支持一个给定的选项。

如同对限制的处理一样,SUS定义了三种处理方法:

  • 编译时选项定义在<unistd.h>中;
  • 与文件或目录无关的选项可用sysconf函数来确定;
  • 与文件或目录相关的选项可用pathconf或fpathconf函数来确定;

如果符号常量未定义,则必须使用sysconf、pathconf或fpathconf以决定该选项是否受到支持。如果该平台定义了符号常量,则有以下三种可能:

  • 如果符号常量的定义值为-1,那么该平台不支持相应的选项;
  • 如果符号常量的定义值大于0,那么该平台支持相应的选项;
  • 如果符号常量的定义值为0,则必须调用sysconf、pathconf以确定相应的选项是否受到支持;

功能测试宏:

大多数实现在头文件中除了定义很多POSIX符号和XSI符号,也在这些头文件中加上了它们自己的定义。如果编译一个程序时,只希望使用POSIX的定义而不使用任何实现定义的限制,那么就需要定义常量_POSIX_C_SOURCE,所有的POSIX头文件都使用此常量。当定义此常量时,就能排除任何实现专有的定义。

常量_POSIX_C_SOURCE以及_XOPEN_SOURCE被称为功能测试宏。

另一个功能测试宏是:__STDC__,它由符合ISO C标准的C编译器自动定义。这就允许我们编写ISO C编译器和非ISO C编译器都能编译的程序。尽管大多数编译器都支持ISO C标准,但是很多头文件中仍旧使用__STDC__功能测试宏。

基本系统数据类型:

头文件<sys/types.h>中定义了某些与实现有关的数据类型,他们被称为基本系统数据类型(primitive system data type)。还有很多这种数据类型定义在其它头文件中。在头文件中,这些数据类型都是用C的typedef功能来定义的,它们绝大多数都以_t结尾。

用这种方法定义了这些数据类型后,就不再需要考虑因系统而异的程序实现细节了。

标准之间的冲突:

就整体而言,这些不同的标准之间配合得相当好。但它们之间也有一些差别,例如ISO C和POSIX.1标准之间就存在一些差别,而SUS v3本身就是POSIX.1的超集。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 17:43:49

UNIX环境高级编程(4):UNIX标准化及实现(2)的相关文章

Unix环境高级编程

Advanced Programming in the UNIX Environment Second Edition Unix 环境高级编程 第二版 目录: 第一章:UNIX基础知识 第二章:UNIX标准化及实现 第三章:文件I/O 第四章:文件和目录 第五章:标准I/O库 第六章:系统数据文件盒信息 第七章:进程环境 第八章:进程控制 第九章:进程关系 第十章:信号 第十一章:线程 第十二章:线程控制 第十三章:守护线程 第十四章:高级I/O 第十五章:进程间通信 第十六章:网络IPC:套接

《UNIX环境高级编程(第3版)》

<UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison-Wesley Professional Computing Series) 原出版社: Addison-Wesley Professional 作者: (美)W. Richard Stevens    Stephen A. Rago 译者: 戚正伟 张亚英 尤晋元 出版社:人民邮电出版社 ISBN:9787

Unix 环境高级编程

1 UNIX 环境高级编程 2 目录 3 1.Unix基础知识 4 2.Unix标准化及实现 5 3.文件I/O 6 4.文件盒目录 7 5.标准I/O库 8 6.系统数据文件和信息 9 7.进程环境 10 8.进程控制 11 9.进程关系 12 10.信号 13 11.线程 14 12.线程控制 15 13.守护线程 16 14.高级I/O 17 15.进程间通信 18 16.网络IPC:套接字 19 17.高级进程间通信 20 18.终端I/O 21 19.伪终端 22 20.数据库函数库

Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字 . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录 (四) 一起学 Unix 环境高级编程 (APUE) 之 系统数据文件和信息 (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境 (六) 一起学 Unix 环境高级编程 (APU

Linux - Unix环境高级编程(第三版) 代码编译

Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebook.com/code3e.html 2. 安装依赖库:sudo apt-get install libbsd-dev  3. 进入下载目录make 4. 复制头文件和动态链接库 sudo cp ./include/apue.h /usr/include/ sudo cp ./lib/libapue

UNIX环境高级编程笔记之文件I/O

一.看图说话 一图胜过千言,看图! 二.唠一唠 在写之前,先唠几句,<UNIX环境高级编程>,简称APUE,这本书简直是本神书,像我这种小白,基本上每看完一章都是“哇”这种很吃惊的表情.其实大概三年前,那会大三,我就买了这本书,也看过一些,但好像没有留下什么印象,今天再看,依然觉得像新的一样.很大的原因我想是一直以来都在用windows(用windows做开发为什么学不到真正的技术,我想大家都懂的),当然知识结构不完整,学习能力这些就不说了.所以,对于那些致力于想在Linux下做开发的人来说,

《UNIX环境高级编程》学习心得 一

本文内容大部分摘自<UNIX环境高级编程>,附有部分个人心得. 1.unix体系结构 从严格意义上来说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境.我们通常将这种软件称为内核(kernel),因为它相对较小,而且位于环境核心.如图显示unix体系结构. 内核接口被称为系统调用(system call).公用函数库构建在系统调用接口之上,应用程序既可食用公用函数库,也可以使用系统调用.shell是一个特殊的应用程序,为运行其他应用程序提供了一个接口. 从广义上来讲,操作系

OS X下UNIX环境高级编程(第三版)学习日志-第一章ChapterI,编译apue包与第一个例程

1.从网络上获取代码,地址如下apue最新官方下载地址 2.解压到本地 由于最新版本是第三版(3rd Edition),apue.3e,就是我们要的源代码 3.编译源代码 编译过程中笔者并未遇到任何问题,所以建议大家也下载最新版本的代码来学习,贴一下笔者的环境信息 Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple

【转】apue《UNIX环境高级编程第三版》第一章答案详解

原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此,我要感谢网易的一个工程师朋友和室友,没有他们,我不会开始真正的学习这本书,希望大家以后开始慢慢进步.废话少说,直接上课后习题了. UNIX高级编程第一章习题答案: 1.1在系统上验证,除根目录外,目录l和l l是不同的. 答:这个验证有很多方法可使用命令ls .cd.vim等,目录.指向当前目录,目录..指

《Unix环境高级编程》读书笔记 第7章-进程环境

1. main函数 int main( int argc, char *argv[] ); argc是命令行参数的数目,包括程序名在内 argv是指向参数的各个指针所构成的数组,即指针数组 当内核执行C程序时(使用exec函数),在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址——这是由连接器设置的,而连接器则是由C编译器调用.启动例程从内核取得命令行参数和环境变量值,然后按上述方式调用main函数做好安排. 2. 进程终止 有8种方式使进程终止,其中5种