签订契约吧少年!如何查看man page及其含义

发布时间 2023-07-13 23:06:04作者: asandstar

签订契约吧少年!

函数的调用者和实现者之间订立了一个契约——

在调用函数之前,调用者要为实现者提供某些条件;

在函数返回时,实现者要对调用者尽到某些义务。

描述契约:靠函数接口(eg.函数名、参数、返回值)

学习每个库函数时一定要看Man Page!!!

Man Page随时都在我们手边,想查什么只要输入一个命令就能查

为啥你不愿意看man page?

1.英文不好

那还是先学好了英文再学编程吧,否则即使你把教科书书都学透了也一样无法胜任开发工作,因为你没有进一步学习的能力。

2.Man Page的语言不够友好

Man Page不像本书这样由浅入深地讲解,而是平铺直叙。

不过看习惯了就好了,每个Man Page都不长,多看几遍自然可以抓住重点,理清头绪。

3.Man Page通常没有例子

描述一个函数怎么用,一靠接口,二靠文档,而不是靠例子。

函数的用法无非是几种模式,不需要每个函数都得有个例子教你怎么用。

解读Man Page

一开始看不懂硬着头皮也要看,去看Man Page而不是查书!!!

eg. 输man strcpy或strncpy(它俩的作用是把一个字符串拷贝给另一个字符串)

SYNOPSIS部分:这两个函数的原型,以及要用这些函数需要包含哪些头文件。

参数dest、src和n都加了下划线。

 

有时候用户并不想从头到尾阅读整个Man Page,而是想查一下某个参数的含义,通过下划线和参数名就能很快找到所关心的部分。

(dest表示Destination,src表示Source)顾名思义,该函数是把src所指向的字符串拷贝到dest所指向的内存空间

dest是char *型的,而src是const char *型的

src所指向的内存空间在函数中只能读不能改写

dest所指向的内存空间在函数中是要改写的

改写的目的是当函数返回后调用者可以读取改写的结果

可以猜测用法——

char buf[10];
strcpy(buf, "hello");
printf(buf);

strcpy

文档中强调了strcpy在拷贝字符串时会把结尾的'\0'也拷贝到dest中,保证了dest是以Null结尾的字符串

这样做存在一个问题,strcpy只知道src字符串的首地址,不知道长度,它会一直拷贝到'\0'为止,因此dest所指向的内存空间要足够大,否则有可能写越界

char buf[10];
strcpy(buf, "hello world");

不保证src所指向的内存空间以'\0'结尾,也有可能读越界

char buf[10] = "abcdefghij", str[4] = "heII";
strcpy(buf, str);

strcpy函数的实现者通过函数接口无法得知src字符串的长度和dest内存空间的大小

→需要调用者自己保证不会写越界,提供的src参数指向的内存空间应该确保以'\0'结尾

同时:src和dest所指向的内存空间不能有重叠,以下禁止

char buf[10] = "hello";
strcpy(buf, buf+1);

strncpy

strncpy的参数n指定最多从src中拷贝n个字节到dest中

如果拷贝到'\0'就结束,如果拷贝到n个字节还没有碰到'\0',那么也结束

调用者不能确定src字符串的长度,可以规定一个适当的n值,以确保读写不会越界(常让n的值等于dest所指向的内存空间的大小)

char buf[10];
strncpy(buf,"hello world",sizeof(buf));

可能存在的问题:dest有可能不是以'\0'结尾的,再执行printf(buf)就会读越界

→要确保dest以'\0'结尾,可以加一句赋值

char buf[10];
strncpy(buf, "hello world", sizeof(buf));
buf[sizeof(buf)-1] = '\0';

另外,若src字符串全部拷贝完了不足n个字节,那么还差多少个字节就补多少个'\0'

当src字符串的长度大于n时,不但不补多余的'\0',连字符串结尾的'\0'也没有

CONFORMING TO: 这个函数是遵照哪些标准实现的。

NOTES:给出提示信息。

这里指出如何确保strncpy的dest以'\0'结尾,这段代码比较谨慎

由于n是个变量,在执行buf[n- 1]= '\0';之前先检查一下n是否大于0,如果n不大于0,buf[n - 1]就访问越界了,所以要避免出现这种情况

BUGS:说明使用这些函数可能引起的Bug,一定要仔细看

 strcpy比strncpy更不安全,若调用strcpy前不仔细检查src字符串的长度,有可能写越界

void foo(char *str)
{
    char buf[10];
    strcpy(buf, str);
    ...
}

写越界覆盖了保存在栈帧上的返回地址,函数返回时跳转到非法地址,因而出错。

由调用者分配并传给strcpy函数访问的一段内存通常称为缓冲区(Buffer),缓冲区写越界的错误称为缓冲区溢出(Buffer Overflow)

只是出现段错误那还不算严重,更严重的是缓冲区溢出Bug经常被恶意用户利用:

使函数返回时跳转到一个事先设计好的地址,执行一段事先设计好的指令;

如果设计得巧妙甚至可以启动一个Shell,然后随心所欲地执行任何命令