一、 学习过程

编写程序如下:

编译连接并用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语言不定参数的研究的更多相关文章

  1. C语言不定参数

    最近,遇到一个c语言的不定参数问题.其实,对于c语言的不定参数问题,只需要三个函数就可以搞定了.这三个函数的头文件是<stdarg.h>,其实下面的三个函数都是一个宏定义(macro).  ...

  2. C语言函数不定参数实现方式

    函数如何实现不定参数: 由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,提出了指针参数来解决问题. (1)va_ ...

  3. go语言基础之不定参数的传递

    1.不定参数的传递 示例1: package main //必须有一个main包 import "fmt" func myfunc(tmp ...int) { for _, dat ...

  4. golang中不定参数与数组切片的区别

    package main import "fmt" func main() { myfunc1(, , , ) //传递不定数量的参数 myfunc2([], , , }) //传 ...

  5. C技巧:结构体参数转成不定参数

    下面这段程序是一个C语言的小技巧,其展示了如何把一个参数为结构体的函数转成一个可变参数的函数,其中用到了宏和内建宏"__VA_ARGS__",下面这段程序可以在GCC下正常编译通过 ...

  6. 不定参数函数原理以及实现一个属于自己的printf函数

    一.不定参数函数原理 二.实现一个属于自己的printf函数 参考博文:王爽汇编语言综合研究-函数如何接收不定数量的参数

  7. printf不定参数

    title: printf不定参数 tags: C ARM date: 2018-10-21 12:14:58 --- 不定参数的传递 函数调用时参数传递是使用堆栈来实现的,参数入栈顺序是从右向左,在 ...

  8. c++不定参数函数

    不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多.除了格式化输出之外,我实在没看到多少应用.主要原因是这种技术比较麻烦,副作用也比较多,而一般情况下重载函数也足以替 ...

  9. Go语言 可变参数

    最近与同事讨论时,提到Go语言的可变参数,之前没有总结过相关知识点,今天我们介绍一下Go语言的可变参数. 可变参数(Variable Parameters):参数数量可变的函数称之为可变参数函数,主要 ...

随机推荐

  1. Tomcat启动时报错:java.net.BindException: Permission denied <null>:80 【转载】

    本文转载自: http://blog.sina.com.cn/s/blog_4550f3ca0101g37l.html   问题起因:做负载均衡时需要将Web工程与Wap工程同时部署在一台Suse服务 ...

  2. AOJ 0121 广度优先搜索

    题意:7数码问题.在2×4的棋盘上,摆有7个棋子,每个棋子上标有1至7的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格(用0表示),与空格相邻(上下左右)的棋子可以移到空格中,该棋子原先位置成 ...

  3. GMU

    NEXT | 不错过任何一个新产品 百度开源 Mobile UI 组件库,提供 Web app.Pad 端简单易用的 UI 组件 发表评论

  4. WebView redirect https to http

    最新项目大改版,刚好对相关sdk版本做了下升级,target也从19升级到21. 意外发现原先在WebView中加载的网页中的图片全都变得一片白,连默认图片都不给显示. 经过一番测试才发现是由于tar ...

  5. Unity3D——窗体介绍

    这是本人第一次的Unity的博客,主要还是依据雨松MOMO的视频来进行的,由于感觉视频比較直观,对于入门比較快,再加上自己有对应的编程基础,如今看书的话效率不高,所以先看几个视频了解一下大体的流程,感 ...

  6. JavaScript 总结

    1. JavaScript prototype属性是一个对象 当一个函数在定义之后 就会自动获得这个属性.其初始值是一个空对象.新建了一个名为Cat的构造函数,其prototype为一个对象,cons ...

  7. Chapter 2. Overview gradle概览

    2.1. Features //gradle特性 Here is a list of some of Gradle's features. Declarative builds and build-b ...

  8. python运行时间计算之timeit

    timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000) stmt:statement ...

  9. Ajax跨域请求中的Cookie问题(默认不带cookie等凭证)

    1.原生Ajax请求方式,设置跨域请求附带详细参数 var xhr = new XMLHttpRequest(); xhr.open("POST", "http://xx ...

  10. ARGB和RGB

    ARGB 一种色彩模式,也就是RGB色彩模式附加上Alpha(透明度)通道,常见于32位位图的存储结构. ARGB---Alpha,Red,Green,Blue. Alpha-图像通道 如果图形卡具有 ...