关于c语言不定参数的研究
一、 学习过程
编写程序如下:

编译连接并用debug加载,观察main函数的内容:

Showchar函数的内容:


观察发现,main函数要传递两个参数‘a’和2,在汇编代码中是先将2赋给ax,再将ax入栈,然后将a赋给ax,将ax入栈。在showchar函数中,程序将sp赋给bp,再从bp+4处取出形参a赋给al,再将al中的值赋给b800:690h,然后再从bp+6处取出形参b赋给al,再将al中的值赋给b800:691h。可见main函数给showchar传递参数是把要传递的值赋给ax,再将ax入栈,且如果有多个要传递的值,是由后往前将参数入栈。Showchar函数接收参数是将sp赋给bp,然后由bp+4找到栈中存储的参数a,由bp+6找到栈中存储的的参数b,为什么是bp+4和bp+6呢?因为程序在将两个参数入栈后,call指令将showchar的地址入栈占2个字节,在showchar中将bp入栈又占2个字节,所以要由bp+4找到第一个参数的地址。那么我对此提出三个问题:
(1) main函数将char型数据和int型数据入栈是占2个字节,那么如果是float型或者long int型、double型、long double型等超过2字节的变量类型怎么办?
(2) Showchar函数将栈中取出的参数赋给al,为什么2是int型也只赋给一个字节的al?如果是更大的参数怎么办?
(3) 我们注意到这一个指令

是把al赋给es:[bx],是不是所有非ds的段寄存器都要像这样写?
对于第一个问题,我们把程序中的char和int改成float和double看看:

编译连接,用debug查看,main函数为:

Showchar函数为:


发现main函数的入栈值为:4008、0000、0000、0000、4006、6666.
再看showchar函数的内容,查资料发现int 35h的作用是读取中断向量,但是不知道它的具体功能,inc si和les ax,[06fb];int 39的作用是什么呢?
这里我对于c语言的一些语句在汇编里的实现还是有的不理解,但是这不是我们研究的重点,既然暂时弄不懂,就先跳过这个问题。
再看第三个问题,发现所有es作段地址的指令都是如上格式,ds作段寄存器的指令都把ds省略了。
再来看下一个程序:

编译连接,用debug加载查看,main函数为:


Showchar函数为:



观察C语言的showchar函数可以发现:第一个参数n是要显示的参数数量,第二个参数color是要显示的参数颜色,之后的就是要显示的参数。Showchar函数通过参数n来知道要显示多少个字符。然后通过循环来调用寄存器从栈中提取参数。
但是printf函数的参数是要直接输出的,没有一个参数是告诉它下面有多少个参数。但是printf里面是要输入%c或者%d,那么函数是通过统计%c和%d的数量来判断要输出多少参数的吗?我们写一个printf函数来看看:

编译连接并用debug加载有:

这里是将参数1和2入栈,再入栈194,然后执行printf函数,那么194有什么作用呢?查阅资料知,程序将%c和%d等符号放在偏移地址0194处,结尾加0,通过统计该地址处的%个数来确定要输出的字符数量。所以peintf函数和showchar函数的区别就是showchar函数参数个数已给出而printf函数是要根据%c或%d个数来确定参数个数而已。那么我们要实现简单的printf函数,可以在showchar函数的基础上来改动。
下面是网上找的代码:
void printf(char *,...);
int pow(int, int);
main()
{
/*printf("I think this is interesting :%c and %c and %c",0x61,0x62,0x63);*/
printf("No.%d,%d,%d,this is me %c ing yuan",,,,'Q');
}
void printf(char *des, ...)
{
/*first sure the length of string des*/
int len=;
int i=;
int showp=; /*define the point of showing chars*/
int parap=; /*define of parameter position in stack*/
int intValueLength=;
int signalNum=;
/*calculate length of stirng des */
while(des[i]!='/0')
{
len++;
i++;
}
i=;
while(des[i]!='/0')
{
if(des[i]=='%')
{
/*check type of value user want to show.*/
if(des[i+]=='d')
{
/*here show integer value*/
int showIntValue=*(int *)(_BP++parap+parap); /*here, we show understand that define one char point value, we just push the point value into stack, but not the string value*/
int reValue=showIntValue;
/* *(int far *)(0xb8000000+160*10+80+showp+showp)=showIntValue;
*(int far *)(0xb8000000+160*10+81+showp+showp)=2;*/
i+=;
parap++;
intValueLength=;
/*here we calculate the length of integer value we want to show ,and then we can sure the next value show position*/
while(reValue/!=)
{
intValueLength++;
reValue/=;
}
/*first calculate the length of unmber and show every sigal positon number of Integer */
signalNum = showIntValue/pow(,--intValueLength);
*(char far *)(0xb8000000+*++showp+showp)=signalNum+; /*show the highest signal number*/
*(char far *)(0xb8000000+*++showp+showp)=;
showp++;
while(intValueLength!=)
{
showIntValue=showIntValue-signalNum*pow(,intValueLength);
signalNum= showIntValue/pow(,--intValueLength);
*(char far *)(0xb8000000+*++showp+showp)=signalNum+; /*show the highest signal number*/
*(char far *)(0xb8000000+*++showp+showp)=;
showp++;
}
/*showp+=intValueLength;*/
}
else if (des[i+]=='c')
{
/*here show charactor value*/
*(char far*)(0xb8000000+*++showp+showp)=*(int *)(_BP++parap+parap); /*value of _BP and distance address of CALL order*/
*(char far*)(0xb8000000+*++showp+showp)=;
parap++;
showp++;
i+=;
}
else /*direct show char value in string des*/
{
*(char far *)(0xb8000000+*++showp+showp)=*(int *)(*(int *)(_BP+)+i);
i++;
showp++;
}
}
else /*also direct to show char in des*/
{
*(char far *)(0xb8000000+*++showp+showp)=*(int *)(*(int *)(_BP+)+i);
i++;
showp++;
}
}
}
int pow(int index,int power)
{
int finalValue=;
if(power==);
else
{
while(power!=)
{
finalValue=finalValue*index;
power--;
}
}
return finalValue;
}
二、 解决的问题
(1) 使用es+偏移地址时,查看指令,段寄存器会独自占一条指令。
(2) Main函数是如何给showchar传递参数的?showchar是如何接受参数的?
答:main函数将参数入栈,showchar用bp寄存器在栈中提取参数。
(3) showchar函数是如何知道要显示多少个字符的?printf是如何知道有多少个参数的?
答:showchar函数是通过第一个参数n知道要显示字符数量的,printf是通过第一个字符串中%c和%d的数量来知道要显示字符数量的。
三、 未解决的问题
(1) main函数将char型数据和int型数据入栈是占2个字节,那么如果是float型或者long int型、double型、long double型等超过2字节的变量类型怎么办?
(2) Showchar函数将栈中取出的参数赋给al,为什么2是int型也只赋给一个字节的al?如果是更大的参数怎么办?
关于c语言不定参数的研究的更多相关文章
- C语言不定参数
最近,遇到一个c语言的不定参数问题.其实,对于c语言的不定参数问题,只需要三个函数就可以搞定了.这三个函数的头文件是<stdarg.h>,其实下面的三个函数都是一个宏定义(macro). ...
- C语言函数不定参数实现方式
函数如何实现不定参数: 由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,提出了指针参数来解决问题. (1)va_ ...
- go语言基础之不定参数的传递
1.不定参数的传递 示例1: package main //必须有一个main包 import "fmt" func myfunc(tmp ...int) { for _, dat ...
- golang中不定参数与数组切片的区别
package main import "fmt" func main() { myfunc1(, , , ) //传递不定数量的参数 myfunc2([], , , }) //传 ...
- C技巧:结构体参数转成不定参数
下面这段程序是一个C语言的小技巧,其展示了如何把一个参数为结构体的函数转成一个可变参数的函数,其中用到了宏和内建宏"__VA_ARGS__",下面这段程序可以在GCC下正常编译通过 ...
- 不定参数函数原理以及实现一个属于自己的printf函数
一.不定参数函数原理 二.实现一个属于自己的printf函数 参考博文:王爽汇编语言综合研究-函数如何接收不定数量的参数
- printf不定参数
title: printf不定参数 tags: C ARM date: 2018-10-21 12:14:58 --- 不定参数的传递 函数调用时参数传递是使用堆栈来实现的,参数入栈顺序是从右向左,在 ...
- c++不定参数函数
不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多.除了格式化输出之外,我实在没看到多少应用.主要原因是这种技术比较麻烦,副作用也比较多,而一般情况下重载函数也足以替 ...
- Go语言 可变参数
最近与同事讨论时,提到Go语言的可变参数,之前没有总结过相关知识点,今天我们介绍一下Go语言的可变参数. 可变参数(Variable Parameters):参数数量可变的函数称之为可变参数函数,主要 ...
随机推荐
- 可伸缩性/可扩展性(Scalable/scalability)
原文地址:http://www.jdon.com/scalable.html 可伸缩性(可扩展性)是一种对软件系统计算处理能力的设计指标,高可伸缩性代表一种弹性,在系统扩展成长过程中,软件能够保证旺盛 ...
- [Design Pattern] Iterator Pattern 简单案例
Iterator Pattern,即迭代时模式,按照顺序依次遍历集合内的每一个元素,而不用了解集合的底层实现,属于行为类的设计模式.为了方便理解记忆,我也会称其为遍历模式. 下面是一个迭代器模式的简单 ...
- UIAlertController 的使用——NS_CLASS_AVAILABLE_IOS(8_0)
UIAlertView 随着苹果上次iOS 5的发布,对话框视图样式出现在了我们面前,直到现在它都没有发生过很大的变化.下面的代码片段展示了如何初始化和显示一个带有“取消”和“好的”按钮的对话框视图. ...
- iOS 通过个推 推送原理
目前使用过的第三方推送很多,有极光, 友盟,个推等,现在主要针对个推,谈谈我对推送流程的理解. 在项目中,如果想要实现评论 推送功能 需要进行以下步骤: 1. 在用户登录的时候 通过 [GeTui ...
- django 执行原始SQL
二.知识点总结 When the model query APIs don’t go far enough, you can fall back to writing raw SQL. go far ...
- Android 关于获取摄像头帧数据解码
由于Android下摄像头预览数据只能 ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...
- raid5什么意思?怎样做raid5?raid5 几块硬盘?
一.raid什么意思? RAID是"Redundant Array of Independent Disk"的缩写,raid什么意思了?说白了,中文翻译过来通俗的讲就是磁盘阵列的意 ...
- JAVA WEB实现前端加密后台解密
最近在研究登陆密码的加密,下边上具体代码,只是给出核心代码,具体的代码视业务而定吧,给位有什么问题或者意见请留言. 加密方法用的是AES-128-CBC,BASE64用的是org.apache.com ...
- Java基础知识强化87:BigInteger类之BigInteger加减乘除法的使用
1. BigInteger加减乘除法的使用 public BigInteger add(BigInteger val):加 public BigInteger subtract(BigInteger ...
- 刚接触js感觉好吃力啊
我是一个新手,最近刚刚开始学习js这门语言,感觉好难,有一种无从下手的感觉,不知道应该从哪里学习,虽然也看了很多的书,但是对于一个没有计算机基础的人来说,真的是一种煎熬,每一个名词都要去查.万事开头难 ...