目录
  1. 1. 标准IO库
    1. 1.1. 流和对象
    2. 1.2. 缓存
    3. 1.3. 标准IO库函数
      1. 1.3.1. 设置缓存
      2. 1.3.2. 打开和关闭流
      3. 1.3.3. 读和写流
        1. 1.3.3.1. 输入函数
        2. 1.3.3.2. 输出函数
      4. 1.3.4. 每次一行IO
      5. 1.3.5. 二进制IO
      6. 1.3.6. 定位流
      7. 1.3.7. 格式化IO
        1. 1.3.7.1. 格式化输出
        2. 1.3.7.2. 格式化输入
      8. 1.3.8. 实现细节
      9. 1.3.9. 临时文件
APUE学习笔记-标准IO库

标准IO库

标准io库就是C语言用来处理流和文件的一个库,它是对文件IO系统调用(不同操作系统提供不同的系统调用)的封装,这使得这套标准库能够隐藏细节,可以移植到其他平台上。

流和对象

对于标准IO库来说,它们的操作是围绕流进行的。标准库将需要操作的文件与流关联,通过流来对文件进行各种操作。当打开一个流时,标准IO函数返回一个FILE对象的文件结构指针,这样就能通过文件结构指针对文件进行操作。
文件结构指针就是一个指向文件对象的指针,文件对象则是将文件所有信息封装为一个对象结构,这样的话能够进行读写字符、字符串、格式化数据、二进制数据多种形式的操作。

缓存

相对于IO系统调用直接操作文件描述符,没有设置缓存,只能读写二进制文件(因为没有设置缓存,每次只能有一个字节被接收变量接收)。IO标准库则设置了缓存,它在内存中开辟一个缓存区。当执行读文件操作时,会先将数据读入缓存区,装满后从缓存区依次读入接收变量。这样使得能够读写字符文件(一个字符多个字节)等多字节文件。

  • 缓存类型
    标准IO提供三种缓存方式
    全缓存:填满缓存区才进行IO操作(标准输入和标准输出不涉及交互,才是全缓存)
    行缓存:遇到换行符就执行IO操作
    不到缓存:不对字符进行缓存(标准出错是不带缓存)

标准IO库函数

设置缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
/*******************************************

mode 缓冲类型:
_IOFBF 全缓存
_IOLBF 行缓存
_IONBF 不带缓存
注意:
buf指向一个长度为BUFSIZ(定义在<stdio.h>中)的缓存则该流就是全缓存的
buf设置为NULL则关闭缓存
********************************************/

/*******************************************
FILE *fp : *fp是一个文件指针,指向的是一个文件结构对象
char *buf : 缓冲区,缓存fp文件中获取的数据,通常是一个数组(这个缓冲区大小是固定的,通常是系统指定的大小)
return : 返回值无
function : 用于将指定的缓冲区(buf)与特定文件(fp)关联,实现操作缓冲区时直接操作文件流的功能。用来设置打开或者关闭缓存机制,操作fp文件指针指向的文件对象
notice : setbuf相当于调用setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZE)
********************************************/
void setbuf(FILE *fp , char *buf);

/*******************************************
FILE *fp : *fp是一个文件指针,指向一个文件结构对象
char *buf : 缓冲区,缓存fp文件中获取的数据,通常是一个数组
int mode : mode指定缓冲类型(注释一)
size_t size : 指定缓冲区大小
return : 成功返回0,出错返回非0
function : 精确的指定缓冲区大小和类型,再将缓冲区(buf)与特定文件关联(fp),从而操作文件流
********************************************/
int setvbuf(FILE *fp , char *buf , int mode , size_t size);
/*******************************************
FILE *fp : 文件指针
return : 成功返回0,出错返回EOF
function : 用来刷新流,使该流所有未写的数据都被传递到内核
notice : fp=NULL时,函数将刷新所有输出流
********************************************/
int fflush(FILE *fp);
打开和关闭流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
/*******************************************

type 参数类型:
r 以只读方式打开文件,该文件必须存在。
  r+ 以可读写方式打开文件,该文件必须存在。
  rb+ 读写打开一个二进制文件,只允许读写数据。
  w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
  w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
  wb 只写打开或新建一个二进制文件;只允许写数据。
  wb+ 读写打开或建立一个二进制文件,允许读和写。
  a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
  a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
  ab+ 读写打开一个二进制文件,允许读或在文件末追加数据。


POSIX.1要求以这种方式创建的文件具有下列存取许可权:
S_IRUSR : 文件属主读
S_IWUSR : 文件属主写
S_IRGRP : 文件属组读
S_IWGRP : 文件属组写
S_IROTH : 其他人可读
S_IWOTH : 其他人可写
********************************************/

/*******************************************
const char *pathname : 文件路径,指针指向一个文件路径字符串(路径不能被修改,需要添加const)
const char *type : 文件打开方式(参见②)
return : 成功返回文件指针,出错返回NULL
function : 指定打开文件方式,通过文件路径pathname打开文件
********************************************/
FILE *fopen(const char *pathname , const char *type);

/*******************************************
const char *pathname : 文件路径,指针指向一个文件路径字符串(路径不能被修改,需要添加const)

const char *type : 文件打开方式(参见②)
FILE *fp : 文件指针,指向文件结构对象
return : 成功返回文件指针,出错返回NULL
function : 指定打开文件方式,在一个特定的流上(由fp指示),打开一个指定的文件(路径名由pathname指示)
********************************************/
FILE *freopen(const char *pathname , const char *type , FILE *fp);
/*******************************************
int fd : 文件描述符,是一个正整数
const char *type : 文件打开方式(参见②)
return : 成功返回文件指针,出错返回NULL
function : 取一个现存的文件描述符(通过open,dup,dup2,fcntl,pipe函数得到),并使一个标准的IO流与该描述符相结合, 此函数常用于由创建管道和网络通信通道函数获得的插述符。因为这些特殊类型文件不能用标准IO fopen函数打开,需要调用设备专用函数获得文件描述符。然后使一个标准IO流与该描述符相结合
********************************************/
FILE *fdopen(int fd , const char *type);

/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 成功返回0,出错返回EOF
function : 关闭一个打开的指定文件流
********************************************/
int fclose(FILE *fp);
读和写流

一旦打开了流,可以在三种不同的 非格式化IO 中进行选择,对其进行读写操作。

  • 每次一个字符的IO
    一次读或者写一个字符,如果流带缓冲,则处理所有缓冲
  • 每次一行的IO
    使用fgets和fputs一次读或写一行,每行以一个换行符终止。
  • 直接IO
    fread和fwrite函数支持,每次IO操作读或写某种数量的对象,每个对象具有指定长度。通常用于从二进制文件中读或写一个结构
输入函数

用于一次读一个字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

/*******************************************
注意:
使用unsigned char不带符号:
如果最高位为1(如果是有符号,1000 0000这个最高位为1为符号位,表示负数;如果是无符号,最高位不是符号位,就算为1也表示一个正数)也不会使返回值为负
要求返回值是int类型:
因为已发生错误或已到达文件尾端的指示值EOF值为-1,是一个负数,unsigned char不能表示,需要使用int类型
********************************************/
#include <stdio.h>
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 成功返回下一个字符(int类型,unsigned char类型强转),出错返回EOF(-1)
function : 与fgetc等价,不同在于可被实现为宏
notice :
1 不应当具有副作用的表达式.(常量,只能为右值,效率高)
2 fgetc一定是一个函数,可以得到其地址。允许将fgetc地址作为参数传递
********************************************/
int getc(FILE *fp) ;

/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 成功返回下一个字符(int类型,unsigned char类型强转),出错返回EOF(-1)
function : 从文件流中读取下一个字符
notice : 这里返回一个int类型是因为EOF是一个远大于char类型范围的数,只能使用int类型来接收。如果返回unsigned char型(不能为负数),就永远不能接收EOF(在宏中定义为-1),int类型能够接收
********************************************/
int fgetc(FILE *fp);

/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 成功返回下一个字符(int类型,unsigned char类型强转),出错返回EOF(-1)
function : 等同于getc(stdin),从标准输入获取
********************************************/
int getchar(void) ;
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 若条件为真则为非 0(真),否则为0(假)
function : 返回出错标志
********************************************/
int ferror(FILE *fp);

/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 若条件为真则为非 0(真),否则为0(假)
function : 返回文件结束标志
********************************************/
int feof(FILE *fp);

/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 无返回值
function : 清除出错标志和结束标志
********************************************/
void clearerr(FILE *fp);

/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
int c : 要读的字符
return : 若成功则为c,若出错则为EOF
function : 从一个流读字符c之后,可以调用这个函数将字符c再送回流中。送回流中的字符以后可以从流中读出,但读出字符顺序与送回顺序相反。
********************************************/
int ungetc(int c , FILE *fp);
输出函数

对应输入函数,每个输入函数都有一个输出函数,性质与上面输入函数相对应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
int c : 要取的字符
return : 若成功则为c,若出错则为EOF
function : 与fgetc等价,不同在于可被实现为宏
********************************************/
int putc(int c , FILE *fp);
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
int c : 要取的字符
return : 若成功则为c,若出错则为EOF
function : 将一个字符c,强制转换为unsigned char , 写入流中
********************************************/
int fputc(int c , FILE *fp);
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
int c : 要取的字符
return : 若成功则为c,若出错则为EOF
function : 等价于putc(c, stdout)
********************************************/
int putchar(int c);
每次一行IO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
获取输入缓存
*/
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
int n : 指定缓存大小
char *buf : 用于缓存读取到的字符
return : 若成功则为buf,若已处文件尾端或出错则为NULL
function : 从流(fp)中读取小于n个字符,并存储到buf(字符串指针)中,遇到EOF或者换行符停止。该缓存一个NULL字符结尾
********************************************/
char *fgets(char *buf , int n , FILE *fp);
/*******************************************
return : 若成功则为 buf,若已处文件尾端或出错则为NULL
function : 尽量不要使用,不能指定缓存长度,可能造成缓存越界
********************************************/
char *gets(char *buf);

/*
输出一行
*/
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
const char *str : 指向一个字符串,这个字符串是一个常量,不能修改
return : 若成功则为非负值,若出错则为EOF
function : 将一个以NULL字符终止的字符串(str)写到指定的流(fp),终止符NLL不写出
********************************************/
int fputs(const char *str , FILE *fp);
/*******************************************
const char *str : 指向一个字符串,这个字符串是一个常量,不能修改
return : 若成功则为c,若出错则为EOF
function : 将一个以NULL字符终止的字符串写到标准输出,终止符不写出(尽量避免使用)
********************************************/
int puts(const char *str);
二进制IO

二进制IO,我么需要一次读或写整个结构
fgetc和fputs一次只能读写一字节
其中可能会有null字符,所以不能用fputs和fgets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*******************************************
const char *ptr : 指向二进制数据的开始地址
size_t size : 二进制数据大小
size_t nobj : 对象个数
FILE *fp : 文件指针,指向一个文件结构对象
return : 读的对象数(也就是nobj)
function :指定需要读取的对象个数,指定需要读取的大小, 从流fp中读取数据,放入以ptr为开始地址的后面size大小的内存空间中
********************************************/
size_t fread(void *ptr , size_t size , size_t nobj , FILE *fp);
/*******************************************
const char *ptr : 指向二进制数据的开始地址
size_t size : 二进制数据大小
size_t nobj : 对象个数
FILE *fp : 文件指针,指向一个文件结构对象
return : 写的对象数(也就是nobj)
function : 指定需要读取的对象个数,指定需要读取的大小,将以ptr为开始地址的后面内存空间中的数据写入流fp中
********************************************/
size_t fwrite(const void *ptr , size_t size , size_t nobj , FILE *fp);
定位流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
/*
ftell和fseek
是Unix函数,他们假定文件的位置可以存放在一个长整型中。
只能以字节为计量单位
*/
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 若成功则为当前文件位置指示,若出错则为-1L
function : 函数通过fp流获取这个流指向的位置指示符指示的当前值
notice : 对于二进制文件,位置指示符是从文件起始位置开始度量,以字节为单位
********************************************/
long ftell(FILE *fp);
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
long offset : 文件偏移量,以字节为单位
int whence : 设置文件开始位置(SEEK_SET(文件起始位置),SEEK_CUR(当前位置),SEEK_END(文件结束位置))
return : 若成功则为0,若出错则为非0
function : 函数通过fp获取文件流,通过whence设置函数在哪里开始,通过offset设置whence后面需要有多少个字节
notice :
1 对于二进制文件,位置指示符是从文件起始位置开始度量,以字节为单位
  2 对于文本文件,whence一定要在文件起始位置,offset只能是0或者对该文件ftell返回的值
********************************************/
int fseek(FILE *fp , long offset , int whence);
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
return : 无返回值
function : 将流中的文件位置指示符放置到文件开始位置
********************************************/
void rewind(FILE *fp);


/*
fgetpos和fsetpos函数
是ANSIC C标准函数
设置了一个fpos_t对象,将当前值存入对象中,使得值能重复利用

*/
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
fpos_t *pos : pos指向的对象用于存放当前值
return : 若成功则为 0,若出错则为非 0
function : fgetpos将文件指示器的当前位置存入有pos指向的对象中
********************************************/
int fgetpos(FILE *fp , fpos_t *pos);
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
fpos_t *pos : pos指向的对象用于存放当前值(这个值是从fgetpos的pos中获取的,是固定的)
return : 若成功则为 0,若出错则为非 0
function : fsetpos取出pos中的当前值,用这个值来定位到文件流中的该位置
********************************************/
int fsetpos(FILE *fp , const fpos_t *pos);
格式化IO
格式化输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio,h>
/*
printf,fprintf,sprintf是非常常用的格式化输出函数
与之对应的则是scanf,fscanf,sscanf三个格式化输入函数

*/
/*******************************************
char *format : 提示信息,包括指定格式化格式
... : 需要格式化的数据
return : 若成功则为输出字符数,若输出出错则为负值
function : 将格式化数据写到标准输出
********************************************/
int printf(const char *format , ...);
/*******************************************
FILE *fp : 文件指针,指向一个文件结构对象
char *format : 提示信息,包括指定格式化格式
... : 需要格式化的数据
return : 若成功则为输出字符数,若输出出错则为负值
function : 将格式化数据写到指定的流fp
********************************************/
int fprintf(FILE *fp , const char *format , ...);
/*******************************************
char *buf : 缓存数组,用于接收格式化数据
char *format : 提示信息,包括指定格式化格式
... : 需要格式化的数据
return : 存入数组的字符数
function : 将格式化的字符串写入缓存数组buf中
notice : 会在数组尾端加入null字节,但不包括在返回值中 可能会造成由buf指向的缓存溢出
********************************************/
int sprintf(char *buf , const char *format , ...);

#include <stdarg,h>
/********************************************
上面三个格式化输出函数的变种,可变参数表变化为va_list宏
va_list : va_list是一种类型(定义在stdarg.h),表示参数列表,和...的功能差不多,但是它可以使用stdarg.h中的函数进行拓展
*********************************************/
int vprintf(const char *format , va_list arg);
int vfprintf(FILE *fp , const char *format , va_list arg);
int vsprintf(char *buf , const char *format , va_list arg);

格式化输入
1
2
3
4
5
6
7
8
9

#include <stdio,h>
/********************************************
这三个格式化输入函数的功能与上面对应的格式化输出函数的功能项对应
return : 返回指定的输入项数,若输入出错,或在任意变化前已至文件尾端则为EOF
*********************************************/
int scanf(const char *format , ...);
int fscanf(FILE *fp , const char *format , ...);
int sscanf(const char *buf , const char *format , ...);
实现细节

总的来说,标准IO函数库中的库函数最终都会调用IO系统调用
因此,每个流都会有与其相关的文件描述符(IO系统调用都是使用文件描述符来进行的)
我们可以使用函数获取文件描述符

1
2
3
4
5
6
7
8
9
#include <stdio.h>

/********************************************
FILE *fp : 文件指针
return : 返回与该流相关的文件描述符
function : 指定文件流,获取该文件流的文件描述符
notice : 如果标准IO库函数需要调用系统调用,则需要用这个函数获取文件描述符来调用
*********************************************/
int fileno(FILE *fp);

我们可以用一个程序来获取标准库的实现细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//#include "../../include/apue.h"
#include "../../include/standard_error.h"
#include <stdio.h>

/***************************************************
const char * : 流的别名,由使用函数者命名
FILE *fp : 使用的流
function : 为特定的流命名,并输出流的缓存类型和缓存大小
****************************************************/
void pr_stdio(const char * , FILE *fp);

int main(void)
{
FILE *fp ;
/* 将一行字符串输出到标准输出 */
fputs("enter any character\n" , stdout);
/* 从标准输入读取字符,如果没有读取到结尾就结束,表示错误 */
if(getchar() == EOF)
{
err_sys("getchar error");
}
fputs("one line to standard error\n",stderr);

pr_stdio("stdin" , stdin); /* 由getchar放入标准输入 */
pr_stdio("stdout" , stdout); /* fputs里的字符输出到标准输出 */
pr_stdio("stderr" , stderr); /* fputs里的字符输出到标准错误 */

if((fp = fopen("/etc/motd" , "r")) == NULL)
{
err_sys("fopen error");
}

/* 从文件流中一个字节一个字节的获取,直到遇上EOF */
if(getc(fp) == EOF)
{
err_sys("getc error");
}

pr_stdio("/etc/motd" , fp);

exit(0);
}

void pr_stdio(const char *name , FILE *fp)
{
printf("stream = %s, " , name);
if(fp->_flags & _IONBF)
{
printf("无缓存");
}else if(fp->_flags & _IOLBF)
{
printf("行缓存");
}else
{
printf("全缓存");
}
/* 在linux下可能没有bufsiz这个属性 */
printf(", buffer size = %d\n" , fp->_bufsiz);
}

/*
结论:
当标准输入、输出连至终端时,它们是行缓存;当它们定向到普通文件则是全缓存
普通文件按系统默认是全缓存

*/
临时文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
/********************************************
char *ptr : 一个指向字符串的指针,用来存放产生的有效路径名字符串
return : 返回指向唯一路径名的指针
function : 产生一个与现在文件名不同的一个有效路径名字符串,每次调用,都会产生一个不同的路径名,最多调用次数是TMP_MAX(stdio.h),放入ptr指向的内存区
notice : ptr=NULL,产生的路径名存放在一个静态区,指向静态区的指针作为函数值返回,下一次调用,会重写静态区
如果不是NULL,则指向长度至少是L_tmpnam个字符的数组(stdio.h)
*********************************************/
char *tmpnam(char *ptr);
/********************************************
return : 若成功则为文件指针,若出错则为NULL
function : 创建一个临时文件,返回一个指向这个临时文件的文件指针
*********************************************/
FILE *tmpfile(void);


/********************************************
directory选择:
选择环境变量TMPDIR作为目录(如果有)
directory非NULL,指定directory为目录
将<stdio.h>中的字符串P_tmpdir作为目录
将本地/tmp目录作为目录
prefix注意:
如果非NULL,最多包含5个字符
const char *directory : 指定需要创建的临时文件所在的目录
const char *prefix : 指定需要创建的临时文件的前缀
return : 返回指向临时文件的唯一路径名的指针
function : 指定临时文件目录和前缀,通过这些创建一个指定目录,指定前缀的临时文件
*********************************************/
char *tempnam(const char *directory , const char *prefix);

tmpnam和tmpfile应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#include "../../include/standard_error.h"
#include <stdio.h>

int main(void)
{
char name[L_tmpnam] , line[MAXLINE] ;
FILE *fp ;

/* 使用tmpnam创建一个有效的路径名字符串,放入静态区中,指向该静态区的指针作为函数返回值 */
printf("%s\n",tmpnam(NULL));

/* 将产生的有效路径名字符串放入name数组中,并将name返回 */
tmpnam(name);
printf("%s\n",name);

/* 创建一个临时二进制文件,返回临时文件对象,关闭程序后将自动删除 */
if((fp = tmpfile()) == NULL)
{
err_sys("tmpfile error");
}
/* 将字符串写入文件对象中 */
fputs("one line of output\n",fp);
/* 将指针复位到起始地址,从起始地址开始读取 */
rewind(fp);
/* 从文件对象中一行一行的获取数据,并放到line数组中 */
if(fgets(line , sizeof(line) , fp) == NULL)
{
err_sys("fgets error");
}
/* 从line数组中去除数据放入标准输出中 */
fputs(line , stdout);
exit(0);
}

tempnam应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "../../include/standard_error.h"
#include <stdio.h>

int main(int argc , char *argv[])
{
/* 第一个argc是命令,第一个参数是目录,第二个参数是前缀 */
if(argc != 3)
{
err_quit("usage:a.out<directory><prefix>");
}

/*
argv[1][0] != '' ? argv[1]:NULL : 如果第一个参数不是空字符串则正常输出,如果是则输出为NULL
argv[2][0] != ' '? argv[2]:NULL : 如果第二个参数不是空字符串则正常输出,如果是则输出为NULL
*/
printf("%s\n",tempnam(argv[1][0] != ' ' ? argv[1]:NULL , argv[2][0] != ' '?argv[2]:NULL));
exit(0) ;
}
文章作者: rack-leen
文章链接: http://yoursite.com/2019/05/03/APUE/APUE%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/APUE%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E6%A0%87%E5%87%86IO%E5%BA%93/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 rack-leen's blog
打赏
  • 微信
  • 支付宝

评论