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小节,或者查阅相关网络文章。