zoukankan      html  css  js  c++  java
  • 关于c语言不定参数的研究

    一、 学习过程

    编写程序如下:

     

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

     

    Showchar函数的内容:

     

     

    观察发现,main函数要传递两个参数‘a’和2,在汇编代码中是先将2赋给ax,再将ax入栈,然后将a赋给ax,ax入栈。在showchar函数中,程序将sp赋给bp,再从bp+4处取出形参a赋给al,再将al中的值赋给b800690h,然后再从bp+6处取出形参b赋给al,再将al中的值赋给b800691h。可见main函数给showchar传递参数是把要传递的值赋给ax,再将ax入栈,且如果有多个要传递的值,是由后往前将参数入栈。Showchar函数接收参数是将sp赋给bp,然后由bp+4找到栈中存储的参数a,由bp+6找到栈中存储的的参数b,为什么是bp+4bp+6呢?因为程序在将两个参数入栈后,call指令将showchar的地址入栈占2个字节,在showchar中将bp入栈又占2个字节,所以要由bp+4找到第一个参数的地址。那么我对此提出三个问题:

    (1) main函数将char型数据和int型数据入栈是占2个字节,那么如果是float型或者long int型、double型、long double型等超过2字节的变量类型怎么办?

    (2) Showchar函数将栈中取出的参数赋给al,为什么2int型也只赋给一个字节的al?如果是更大的参数怎么办?

    (3) 我们注意到这一个指令

     

      是把al赋给es[bx],是不是所有非ds的段寄存器都要像这样写?

    对于第一个问题,我们把程序中的charint改成floatdouble看看:

     

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

     

    Showchar函数为:

     

     

    发现main函数的入栈值为:400800000000000040066666.

    再看showchar函数的内容,查资料发现int 35h的作用是读取中断向量,但是不知道它的具体功能,inc siles 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加载有:

     

    这里是将参数12入栈,再入栈194,然后执行printf函数,那么194有什么作用呢?查阅资料知,程序将%c%d等符号放在偏移地址0194处,结尾加0,通过统计该地址处的%个数来确定要输出的字符数量。所以peintf函数和showchar函数的区别就是showchar函数参数个数已给出而printf函数是要根据%c%d个数来确定参数个数而已。那么我们要实现简单的printf函数,可以在showchar函数的基础上来改动。

    下面是网上找的代码:

      1 void printf(char *,...);
      2 
      3 int pow(int, int);
      4 
      5  
      6 
      7 main()
      8 
      9 {
     10 
     11 /*printf("I think this is interesting :%c and %c and %c",0x61,0x62,0x63);*/
     12 
     13  
     14 
     15 printf("No.%d,%d,%d,this is me %c ing yuan",45,123,8958,'Q');
     16 
     17 }
     18 
     19  
     20 
     21 void printf(char *des, ...)
     22 
     23 {
     24 
     25 /*first sure the length of string des*/
     26 
     27 int len=0;
     28 
     29 int i=0;
     30 
     31 int showp=0; /*define the point of showing chars*/
     32 
     33 int parap=0; /*define of parameter position in stack*/
     34 
     35 int intValueLength=1;
     36 
     37 int signalNum=0;
     38 
     39 /*calculate length of stirng des */
     40 
     41 while(des[i]!='/0')
     42 
     43 {
     44 
     45 len++;
     46 
     47 i++;
     48 
     49 }
     50 
     51 i=0;
     52 
     53  
     54 
     55 while(des[i]!='/0')
     56 
     57 {
     58 
     59 if(des[i]=='%')
     60 
     61 {
     62 
     63 /*check type of value user want to show.*/
     64 
     65 if(des[i+1]=='d')
     66 
     67 {
     68 
     69 /*here show integer value*/
     70 
     71 int showIntValue=*(int *)(_BP+6+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*/
     72 
     73 int reValue=showIntValue;
     74 
     75 /* *(int far *)(0xb8000000+160*10+80+showp+showp)=showIntValue;
     76 
     77 *(int far *)(0xb8000000+160*10+81+showp+showp)=2;*/
     78 
     79 i+=2;
     80 
     81 parap++;
     82 
     83 intValueLength=1;
     84 
     85 /*here we calculate the length of integer value we want to show ,and then we can sure the next value show position*/
     86 
     87 while(reValue/10!=0)
     88 
     89 {
     90 
     91 intValueLength++;
     92 
     93 reValue/=10;
     94 
     95 }
     96 
     97 /*first calculate the length of unmber and show  every sigal positon number of Integer  */
     98 
     99 signalNum = showIntValue/pow(10,--intValueLength);
    100 
    101 *(char far *)(0xb8000000+160*10+80+showp+showp)=signalNum+48; /*show the highest signal number*/
    102 
    103 *(char far *)(0xb8000000+160*10+81+showp+showp)=2;
    104 
    105 showp++;
    106 
    107 while(intValueLength!=0)
    108 
    109 {
    110 
    111 showIntValue=showIntValue-signalNum*pow(10,intValueLength);
    112 
    113 signalNum= showIntValue/pow(10,--intValueLength);
    114 
    115 *(char far *)(0xb8000000+160*10+80+showp+showp)=signalNum+48; /*show the highest signal number*/
    116 
    117 *(char far *)(0xb8000000+160*10+81+showp+showp)=2;
    118 
    119 showp++;
    120 
    121 }
    122 
    123 /*showp+=intValueLength;*/
    124 
    125 }
    126 
    127 else if (des[i+1]=='c')
    128 
    129 {
    130 
    131 /*here show charactor value*/
    132 
    133 *(char far*)(0xb8000000+160*10+80+showp+showp)=*(int *)(_BP+6+parap+parap); /*value of _BP and distance address of  CALL order*/
    134 
    135 *(char far*)(0xb8000000+160*10+81+showp+showp)=2;
    136 
    137 parap++;
    138 
    139 showp++;
    140 
    141 i+=2;
    142 
    143 }
    144 
    145 else /*direct show char value in string des*/
    146 
    147 {
    148 
    149 *(char far *)(0xb8000000+160*10+80+showp+showp)=*(int *)(*(int *)(_BP+4)+i);
    150 
    151 i++;
    152 
    153 showp++;
    154 
    155 }
    156 
    157 }
    158 
    159 else /*also direct to show char in des*/
    160 
    161 {
    162 
    163 *(char far *)(0xb8000000+160*10+80+showp+showp)=*(int *)(*(int *)(_BP+4)+i);
    164 
    165 i++;
    166 
    167 showp++;
    168 
    169 }
    170 
    171 }
    172 
    173 }
    174 
    175  
    176 
    177 int pow(int index,int power)
    178 
    179 {
    180 
    181 int finalValue=1;
    182 
    183 if(power==0);
    184 
    185 else
    186 
    187 {
    188 
    189 while(power!=0)
    190 
    191 {
    192 
    193 finalValue=finalValue*index;
    194 
    195 power--;
    196 
    197 }
    198 
    199 }
    200 
    201 return finalValue;
    202 
    203 }

    二、 解决的问题

    (1) 使用es+偏移地址时,查看指令,段寄存器会独自占一条指令。

    (2) Main函数是如何给showchar传递参数的?showchar是如何接受参数的?

    答:main函数将参数入栈,showcharbp寄存器在栈中提取参数。

    (3) showchar函数是如何知道要显示多少个字符的?printf是如何知道有多少个参数的?

    答:showchar函数是通过第一个参数n知道要显示字符数量的,printf是通过第一个字符串中%c%d的数量来知道要显示字符数量的。

    三、 未解决的问题

    (1) main函数将char型数据和int型数据入栈是占2个字节,那么如果是float型或者long int型、double型、long double型等超过2字节的变量类型怎么办?

    (2) Showchar函数将栈中取出的参数赋给al,为什么2int型也只赋给一个字节的al?如果是更大的参数怎么办?

  • 相关阅读:
    google.guava 实现 限流
    基于 Redisson 的限流 小 demo
    TX-LCN分布式事务-- TCC事务模式(消费者模块)
    TX-LCN分布式事务-- TCC事务模式(生产者模块)
    TX-LCN分布式事务-- LCN事务模式(消费者模块)
    TX-LCN分布式事务-- LCN事务模式(生产者模块)
    TX-LCN分布式事务-- LCN事务模式(eureka模块)
    TX-LCN分布式事务-- LCN事务模式(tm模块)
    TX-LCN分布式事务--学习地址和原理介绍
    LINQ to SQL系列三 使用DeferredLoadingEnabled,DataLoadOption指定加载选项
  • 原文地址:https://www.cnblogs.com/stormpeach/p/4321655.html
Copyright © 2011-2022 走看看