第2章——《Unix标准及实现》

实验环境介绍

  • gcc:4.8.5
  • glibc:glibc-2.17-222.el7.x86_64
  • os:Centos7.4
  • kernel:3.10.0-693.21.1.el7.x86_64

引言

  • 略过

Unix标准化

  • 都是历史,略过

Unix系统实现

  • 都是历史,略过

标准与实现的差异

  • 略过

限制

unix限制
  • 必需的两种限制:
    • 编译时限制(例如:短整型的最大值)
    • 运行时限制(例如:文件名有多少字符)
  • 编译时限制的解决方案:头文件
  • 运行时限制的解决方案 :
    • 与文件和目录无关的运行时限制:sysconf函数
    • 与文件或目录有关的运行时限制:pathconf和fpathconf函数

后面说明

ISO C限制
  • 在limit.h中,如下图:


    <limits.h>中定义的整型大小
  • 测试代码如下:

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

int
main(int argc, char *argv[])
{
    printf("CHAR_BIT: %d\n", CHAR_BIT);
    printf("CHAR_MAX: %d\n", CHAR_MAX);
    printf("CHAR_MIN: %d\n", CHAR_MIN);
    printf("INT_MAX: %d\n", INT_MAX);
    printf("INT_MIN: %d\n", INT_MIN);

    exit(EXIT_SUCCESS);
}

result:
CHAR_BIT: 8
CHAR_MAX: 127
CHAR_MIN: -128
INT_MAX: 2147483647
INT_MIN: -2147483648
POSIX限制
  • posix.1定义了很多设计操作系统实现限制的常量,我们只关心与基本posix.1接口有关的部分。这些限制和常量分为下列7类:
    • 数值限制:LOG_BIT、SSIZE_MAX和WORD_BIT
    • 最小值:如下图,这些最小值并不随系统而改变。(忽略名字中的max)


      <limits.h>中的POSIX最小值
    • 最大值:_POSIX_CLOCKRES_MIN
    • 运行时可以增加的值:CHARCLASS_NAME_MAX、COLL_WEIGHTS_MAX、LINE_MAX、NGROUPS_MAX和RE_DUP_MAX
    • 运行时不变值:如下图等


      POSIX运行时不变值

      线程配置限制实例

      POSIX异步I/O运行时不变值
    • 其他不变值:NL_ARGMAX、NL_MSGMAX、NL_SSETMAX和NL_TEXTMAX
    • 路径名可变值:FILESIZEBITS、LINK_MAX、MAX_CANON、MAX_INPUT、NAME_MAX、PATH_MAX、PIPE_BUF和SYMLINK_MAX

某些变量可能没有在<limits.h>中,所以需要使用sysconf、pathconf、fpathconf来获取

XSI限制
  • XSI定义了代表实现限制的几个常量
    • 最小值:如下图


      XSI最小值
    • 运行时不变值(可能不确定):IOV_MAX和PAGE_SIZE
函数sysconf、pathconf和fpathconf
  • sysconf的限制及其参数如下图


    对sysconf的限制及name参数
  • 测试代码如下

#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define ONE_MB  (1024 * 1024)

int
main(int argc, char *argv[])
{
    // test sysconf
    printf("The number of processors configured is :%ld\n",
        sysconf(_SC_NPROCESSORS_CONF));
    printf("The number of processors currently online (available) is :%ld\n",
        sysconf(_SC_NPROCESSORS_ONLN));
    printf ("The pagesize: %ld\n", sysconf(_SC_PAGESIZE));
    printf ("The number of pages: %ld\n", sysconf(_SC_PHYS_PAGES));
    printf ("The number of available pages: %ld\n", sysconf(_SC_AVPHYS_PAGES));
    printf ("The memory size: %lld MB\n",
        (long long)sysconf(_SC_PAGESIZE) * (long long)sysconf(_SC_PHYS_PAGES) / ONE_MB );
    printf ("The number of files max opened:: %ld\n", sysconf(_SC_OPEN_MAX));
    printf("The number of ticks per second: %ld\n", sysconf(_SC_CLK_TCK));
    printf ("The max length of host name: %ld\n", sysconf(_SC_HOST_NAME_MAX));
    printf ("The max length of login name: %ld\n", sysconf(_SC_LOGIN_NAME_MAX));

    // test
    char pathname[] = "/home";
    printf("NAME_MAX = %ld\n", pathconf(pathname, _PC_NAME_MAX));
    printf("PATH_MAX = %ld\n", pathconf(pathname, _PC_PATH_MAX));
    printf("LINK_MAX = %ld\n", pathconf(pathname, _PC_LINK_MAX));
    printf("MAX_INPUT = %ld\n", pathconf(pathname, _PC_MAX_INPUT));
    printf("MAX_CANON = %ld\n", pathconf(pathname, _PC_MAX_CANON));
    printf("PIPE_BUF = %ld\n", pathconf(pathname, _PC_PIPE_BUF));

    // test fpathconf
    int  files = open(pathname, O_RDONLY);
    printf("NAME_MAX = %ld\n", fpathconf(files, _PC_NAME_MAX));
    printf("PATH_MAX = %ld\n", fpathconf(files, _PC_PATH_MAX));
    printf("LINK_MAX = %ld\n", fpathconf(files, _PC_LINK_MAX));
    printf("MAX_INPUT = %ld\n", fpathconf(files, _PC_MAX_INPUT));
    printf("MAX_CANON = %ld\n", fpathconf(files, _PC_MAX_CANON));
    printf("PIPE_BUF = %ld\n", fpathconf(files, _PC_PIPE_BUF));
    exit(EXIT_SUCCESS);
}

result:
The number of processors configured is :2
The number of processors currently online (available) is :2
The pagesize: 4096
The number of pages: 249657
The number of available pages: 35592
The memory size: 975 MB
The number of files max opened:: 1024
The number of ticks per second: 100
The max length of host name: 64
The max length of login name: 256
NAME_MAX = 255
PATH_MAX = 4096
LINK_MAX = 2147483647
MAX_INPUT = 255
MAX_CANON = 255
PIPE_BUF = 4096
NAME_MAX = 255
PATH_MAX = 4096
LINK_MAX = 2147483647
MAX_INPUT = 255
MAX_CANON = 255
PIPE_BUF = 4096
  • pathconf和fpathconf的限制及name参数如下图


    pathconf和fpathconf的限制及name参数
不确定的运行时限制
  • 前面说的某些限制值可能是不确定的。如果没有在<limits.h>中定义,那么在编译的时候就不能使用它们
  • 路径名:很多程序需要为路径名分配存储区,一般来说,在编译时就为其分配了存储区,而且不同的程序使用不同的幻数(其中很少是正确的)作为数组长度,如256、512、1024或标准I/O常量BUFSIZ。4.3BSD头文件<sys.param.h>(<font color="#dd0000">我的环境上是/usr/include/sys/param.h</font><br />)中的常量MAXPATHLEN才是正确的值,但是很多4.3BSD应用程序并未使用它。POSIX.1师徒用PATH_MAX值来获取,如果<limits.h>中定义了常量PATH_MAX,那就没有任何问题,如果未定义,则需要调用pathconf(但要注意,pathconf的返回值是基于工作目录的相对路径名的最大长度,所以指定根目录为第一个参数,并将得到的返回值加1作为结果值)
  • 测试代码如下
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>

#ifdef PATH_MAX
static long pathmax = PATH_MAX;
#else
static long pathmax = 0;
#endif

static long posix_version = 0;
static long xsi_version = 0;


#define PATH_MAX_GUESS 1024

char *
path_alloc(size_t *sizep)
{
    char *ptr;
    size_t size;

    if (!posix_version)
        posix_version = sysconf(_SC_VERSION);

    if (!xsi_version)
        xsi_version = sysconf(_SC_XOPEN_VERSION);

    if (!pathmax) {
        errno = 0;
        if ((pathmax = pathconf("/", _PC_PATH_MAX)) < 0) {
            int errno_save = errno;
            if (errno_save == 0)
                pathmax = PATH_MAX_GUESS;
            else
                perror("pathconf error for _PC_PATH_MAX:");
        } else
            pathmax++;
    }

    if ((posix_version < 200112L) && (xsi_version < 4))
        size = pathmax + 1;
    else
        size = pathmax;

    if ((ptr = malloc(size)) == NULL)
        perror("malloc error for pathname");

    if (sizep)
        *sizep = size;

    return (ptr);
}

int
main(int argc, char *argv[])
{
    size_t size;
    char *ptr = path_alloc(&size);
    if (ptr)
        printf("alloc size = %zu successfully\n", size);
    else
        printf("alloc failed\n");

    exit(EXIT_SUCCESS);
}

result:
[root@localhost part_2]# ./2_16 
alloc size = 4096 successfully
  • 最大打开文件数:使用POSIX.1的OPEN_MAX来提高移植性
  • 测试代码如下
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>

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

#define OPEN_MAX_GUESS 256

long
open_max(void)
{
    if (!openmax) {
        errno = 0;
        if ((openmax = sysconf(_SC_OPEN_MAX)) < 0) {
            if (!errno)
                openmax = OPEN_MAX_GUESS;
            else
                perror("sysconf error for _SC_OPEN_MAX");
        }
    }

    return (openmax);
}

int
main(int argc, char *argv[])
{
    long openmax = open_max();
    if (openmax < 0)
        printf("open_max get error\n");
    else
        printf("openmax is: %ld\n", openmax);
    exit(EXIT_SUCCESS);
}

result:
[root@localhost part_2]# ./2_17 
openmax is: 1024

选项

  • 如同对限制的处理一样,posix.1定义了3种处理选项的方法
    • 编译时选项定义在<unistd.h>
    • 与文件或目录无关的运行时选项用sysconf函数来判断
    • 与文件或目录有关的运行时选项通过调用pathconf或fpathconf
  • 其他的忽略

功能测试宏

  • 忽略

基本系统数据类型

  • 头文件中定义了某些与实现有关的数据类型。绝大多数都是以_t结尾,用这种方式定义这些数据类型后,就不再需要考虑因系统不同而变化的程序实现细节

  • 如下图


    常用基本数据类型

标准之间的冲突

  • ISO C定义了clock函数,返回进程使用的cpu时间,返回值是clock_t类型值,单ISO C没有规定他的单位。为了将值转换成以秒为单位,需要将其除以在<time.h>中定义的CLOCKS_PER_SEC.POSIX.1定义了times函数,他返回其调用者及其所有终止子进程的cpu时间以及时钟时间。ISO C和POSIX.1用同一种数据类型(clock_t)来保存对时间的测量,但定义了不同单位,所以在使用clock_t类型变量的时候,必须小心

  • 由于ISO C函数较少考虑宿主操作系统,所以POSIX的系统为了兼容性也会实现ISO C函数,signal函数(希望编写可在ISO C环境和较早的UNIX系统中运行的可兼容程序),他和POSIX.1 sigaction函数不同。第10章再来说明

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容