1 / 8
文档名称:

C可变参数及printf实现.pdf

格式:pdf   大小:128KB   页数:8页
下载后只包含 1 个 PDF 格式的文档,没有任何的图纸或源代码,查看文件列表

如果您已付费下载过本站文档,您可以点这里二次下载

分享

预览

C可变参数及printf实现.pdf

上传人:iris028 2022/6/22 文件大小:128 KB

下载得到文件列表

C可变参数及printf实现.pdf

文档介绍

文档介绍:C 语言的变长参数在平时做开发时很少会在自己设计的接口中用到,但我们最常用的接口
printf 就是使用的变长参数接口,在感受到 printf 强大的魅力的同时,是否想挖据一下到底
printf 是如何实现的呢fmt, ... )
{
char *ap;

ap = ((char*)&fmt) + sizeof(fmt);
printf("%d\n", *(int*)ap);

ap = ap + sizeof(int);
printf("%d\n", *(int*)ap);

ap = ap + sizeof(int);
printf("%s\n", *((char**)ap));
}

int main()
{
var_args_func("%d %d %s\n", 4, 5, "hello world");
}

输出结果:
4
5
hello world

var_args_func只是为了演示,并未根据fmt消息中的格式字符串来判断变参的个数和类型,
而是直接在实现中写死了,如果你把这个程序拿到solaris 9 下,运行后,一定得不到正确的
结果,为什么呢,后续再说。先来解释一下这个程序。我们用ap获取第一个变参的地址,我
们知道第一个变参是 4,一个int型,所以我们用(int*)ap以告诉编译器,以ap为首地址的那块
内存我们要将之视为一个整型来使用,*(int*)ap获得该参数的值;接下来的变参是 5,又一
个int型,其地址是ap + sizeof(第一个变参),也就是ap + sizeof(int),同样我们使用*(int*)ap
获得该参数的值;最后的一个参数是一个字符串,也就是char*,与前两个int型参数不同的
是,经过ap + sizeof(int)后,ap指向栈上一个char*类型的内存块(我们暂且称之tmp_ptr, char*tmp_ptr)的首地址,即ap -> &tmp_ptr,而我们要输出的不是printf("%s\n", ap),而是
printf("%s\n", tmp_ptr); printf("%s\n", ap)是意图将ap所指的内存块作为字符串输出了,但是ap
-> &tmp_ptr,tmp_ptr所占据的 4 个字节显然不是字符串,而是一个地址。如何让&tmp_ptr
是char **类型的,我们将ap进行强制转换(char**)ap <=> &tmp_ptr,这样我们访问tmp_ptr只
需要在(char**)ap前面加上一个*即可,即printf("%s\n", *(char**)ap);

前面说过,如果将var_args_func放到solaris上,一定是得不到正确结果的?为什么呢?由于内
存对齐。编译器在栈上压入参数时,不是一个紧挨着另一个的,编译器会根据变参的类型将
其放到满足类型对齐的地址上的,这样栈上参数