《UNIX环境高级编程》笔记 第二章——限制、选项和功能测试宏

1. 限制

1.1 简介

计算机系统由硬件和软件(包含操作系统)两大部分组成,系统能够正常并且稳定地运行既受制于底层硬件资源的限制,比如内存大小,IO数量,总线宽度,CPU主率等,又受制于系统具体实现的限制,比如文件路径和文件名的长度,进程能够打开的最大文件描述符个数,函数栈大小等。很多限制能够在编译或运行时获取,在具有特权用户及硬件资源满足的情况下,有一些限制可以通过命令或函数来改变。

两种类型的限制:

(1) 编译时限制,可在头文件中定义

(2)运行时限制,有两个函数可以取得运行时限制

        与文件或目录无关的运行时限制:sysconf

        与文件和目录有关的运行时限制:pathconf和fpathconf

1.2 函数原型

#include <unistd.h>

long sysconf(int name);

long pathconf(const char *pathname,  int name);

long fpathconf(int fd,  int name);

以_SC_开头的常量用作sysconf函数的name参数,以_PC_开头的常量用作pathconf和fpathconf函数的name参数。pathname可以是一个目录或文件,fd是一个打开的文件描述符(文件或目录)。三个函数若成功则返回相应的值,若失败则返回-1。使用pathconf和fpathconf对pathname和fd有很多限制,如果不满足则返回一个未定义的值。

1.3 实例

#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/param.h>

#define TYPE_SIZE(name) {#name,name}

struct type_size {
	char name[32];
	long long int val;
};

struct type_size types[] = {
	TYPE_SIZE(CHAR_BIT),
	TYPE_SIZE(CHAR_MAX),
	TYPE_SIZE(CHAR_MIN),
	TYPE_SIZE(SCHAR_MAX),
	TYPE_SIZE(SCHAR_MIN),
	TYPE_SIZE(UCHAR_MAX),

	TYPE_SIZE(INT_MAX),
	TYPE_SIZE(INT_MIN),
	TYPE_SIZE(UINT_MAX),

	TYPE_SIZE(SHRT_MAX),
	TYPE_SIZE(SHRT_MIN),
	TYPE_SIZE(USHRT_MAX),

	TYPE_SIZE(LONG_MAX),
	TYPE_SIZE(LONG_MIN),
	TYPE_SIZE(ULONG_MAX), //(long long: maybe overflow)

	TYPE_SIZE(LLONG_MAX),
	TYPE_SIZE(LLONG_MIN),
	TYPE_SIZE(ULLONG_MAX), // (long long: overflow)

#ifdef NAME_MAX 
	TYPE_SIZE(NAME_MAX),
#endif
#ifdef PATH_MAX 
	TYPE_SIZE(PATH_MAX),
#endif
#ifdef OPEN_MAX 
	TYPE_SIZE(OPEN_MAX),
#endif
};

struct type_size resources[] = {
	TYPE_SIZE(FOPEN_MAX),
	TYPE_SIZE(TMP_MAX),
	TYPE_SIZE(FILENAME_MAX),
	TYPE_SIZE(BUFSIZ),
	TYPE_SIZE(NOFILE),
};

int main(int argc, char *argv[])
{
	for (int i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
			printf("%10s: %lld\n", types[i].name, types[i].val);
	}
	printf("***********************************\n");
	for (int i = 0; i < sizeof(resources)/sizeof(resources[0]); i++) {
			printf("%16s: %lld\n", resources[i].name, resources[i].val);
	}

	printf("***********************************\n");

	int fd = -1;
	//if ((fd = open("./limits.c", O_RDONLY)) < 0) {
	if ((fd = open(".", O_RDONLY)) < 0) {
			perror("open error");
	}
#ifdef _PC_NAME_MAX
	// printf("NAME_MAX: %ld\n", sysconf(_PC_NAME_MAX));
	printf("NAME_MAX: %ld\n", pathconf("/", _PC_NAME_MAX));
	if (fd > 0) {
			printf("NAME_MAX2: %ld\n", fpathconf(fd, _PC_NAME_MAX));
	}
#endif
#ifdef _PC_PATH_MAX
	// printf("PATH_MAX: %ld\n", sysconf(_PC_PATH_MAX));	
	printf("PATH_MAX: %ld\n", pathconf("/", _PC_PATH_MAX));
	if (fd > 0) {
			printf("PATH_MAX2: %ld\n", fpathconf(fd, _PC_PATH_MAX));
	}
#endif
#ifdef _SC_OPEN_MAX
	printf("OPEN_MAX: %ld\n", sysconf(_SC_OPEN_MAX));	
#endif

	return 0;
}

2. 选项和功能测试宏

2.1 简介

不同的类UNIX系统和不同的接口标准之间实现和支持的功能不尽相同,即使相同系统和标准也有版本之间的区别。因此,如果要编写可移植的应用程序,就需要做到能够兼容这些差异,选项和功能测试宏的使用能够大大提高程序的可移植性,功能测试宏还可以作为一些功能的开关(可以理解为条件编译)。

有三种处理选项的方法:

(1 )编译时选项定义在头文件中(unistd.h)

(2 )与文件或目录无关的运行时选项用sysconf判断

(3 )与文件和目录有关的运行时选项用pathconf和fpathconf判断

函数原型如1.2,前缀为_POSIX的name参数必须替换为_SC或_PC,前缀为_XOPEN的name参数需要在其前面加上_SC或_PC。3种平台支持状态:

 (1)如果选项常量没有定义或为-1,则平台不支持该选项

 (2)如果选项常量定义为大于0,则平台支持该选项

 (3)如果选项常量定义为0,则必须调用sysconf、pathconf和fpathconf来判断

功能测试宏的man手册:man 7 feature_test_macros 

2.2 实例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>

#define TEST_OPTION(name, parm) do { \
	if (name < 0) { \
		printf("The " #name " option is not supported (<0)\n"); \
	} else if (name == 0) { \
		int ret = -1; \
		if (strstr(#parm, "PC") != NULL) { \
			ret = pathconf(".", parm); \
		} else { \
			ret = sysconf(parm); \
		} \
		if (ret > 0) { \
			printf("The " #name " option is supported (=0)\n"); \
		} else { \
			printf("The" #name " option is not supported (=0)\n"); \
		} \
	} else{ \
		printf("The " #name " option is supported (>0)\n"); \
	} \
} while (0)

int main()
{
	printf("************* option ***************\n");
#ifdef _POSIX_NO_TRUNC
	TEST_OPTION(_POSIX_NO_TRUNC, _PC_NO_TRUNC);
#else
	printf("The _POSIX_NO_TRUNC option is not defined\n");
#endif
	
#ifdef _POSIX_SAVED_IDS
	TEST_OPTION(_POSIX_SAVED_IDS, _SC_SAVED_IDS);
#else
	printf("The _POSIX_SAVED_IDS option is not defined\n");
#endif
	
#ifdef _POSIX2_SYMLINKS
	TEST_OPTION(_POSIX2_SYMLINKS, _SC_SYMLINKS);
#else
	printf("The _POSIX2_SYMLINKS option is not defined\n");
#endif
	
#ifdef _XOPEN_CRYPT
	TEST_OPTION(_XOPEN_CRYPT, _SC_XOPEN_CRYPT);
#else
	printf("The _XOPEN_CRYPT option is not defined\n");
#endif
	
	printf("************* feature_test_macros ***************\n");

//#define _POSIX_C_SOURCE 200809L

#if (  _BSD_SOURCE || _SVID_SOURCE )
	printf("The scandir function is supported (_BSD_SOURCE and _SVID_SOURCE)\n");
#else
	printf("The scandir function is not supported (_BSD_SOURCE and _SVID_SOURCE)\n");
#if  ( _POSIX_C_SOURCE >= 200809L || _BSD_SOURCE || _SVID_SOURCE )
	printf("The scandir function is supported (_POSIX_C_SOURCE)\n");
	struct dirent **dir_lst;
	if(scandir(".", &dir_lst, NULL, NULL) < 0) {
		printf("Open dir failed\n");
	} else {
		printf("Open dir success\n");
	}
#endif
#endif

	return 0;
}

3. 小结

本文着重初步理解限制、选项和功能测试宏的概念及作用,以及3个函数sysconf、pathconf和fpathcofg的基本用法,欲想更深入了解细节可以去研读《UNIX环境高级编程》(第三版)第二章5、6和7小节,或者查阅相关网络文章。

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值