C语言中函数参数传递的方式。
2009-10-07 00:16
288 查看
/* Windows 环境下,C语言中我们所写的main函数在生成exe文件之后只是整个可执行文件的一部分。当然, * 是最关键的一部分。在main函数中,我们只需要关心如何定义变量,如何赋值,如何进行参数运算等问 * 题,至于如何向系统申请资源,如何在程序结束后释放资源,参数之间如何进行值传递等等问题我们一 * 概不用关心。但对一个完整的程序而言,这同样是至关重要的。这些工作是由我们的连接器完成的。在 * TC2.0当中,有一个叫做c0s.obj的目标文件,它的作用之一是向系统申请资源,之后释放资源,并使程 * 序正常退出。我们在写完程序并编译后,连接器会将c0s.obj与我们的代码生成的obj相连接。生成可正常运行的exe文件。 * * * * 在C语言中,参数的传递是通过栈来实现的,栈资源的申请就是上面提到的c0s.obj的工作之一。以下是 * C语言中参数传递的一个例子。 * 下面是C语言代码。 */ void show_char(int n, int color,...); main() { show_char(8,2,'a','b','c','d','e','f','g','h'); } void show_char(int n, int color,...) { int a; for (a = 0; a != n; a++) { *(char far *)(0xb8000000 + 160 * 12 + 80 + a + a) = *(int *)(_BP + 8 + a + a); *(char far *)(0xb8000000 + 160 * 12 + 81 + a + a) = color; } } /* 下面是它的汇编代码(使用debug u命令) 1442:01FA 55 PUSH BP ;main函数开始。main函数和show_char函数做的第一件事是一样的,即_BP入栈并将_SP保存在_BP当中。 1442:01FB 8BEC MOV BP,SP ;入栈之前_BP的含义是调用该函数的函数(即该函数的主调函数)的参数在栈中的基址。 ;mov bp,sp之后,bp的含义是本函数中参数的基址。 1442:01FD B86800 MOV AX,0068 1442:0200 50 PUSH AX ;字符参数h入栈 1442:0201 B86700 MOV AX,0067 1442:0204 50 PUSH AX ;字符参数g入栈 1442:0205 B86600 MOV AX,0066 1442:0208 50 PUSH AX ;字符参数f入栈 1442:0209 B86500 MOV AX,0065 1442:020C 50 PUSH AX ;字符参数e入栈 1442:020D B86400 MOV AX,0064 1442:0210 50 PUSH AX ;字符参数d入栈 1442:0211 B86300 MOV AX,0063 1442:0214 50 PUSH AX ;字符参数c入栈 1442:0215 B86200 MOV AX,0062 1442:0218 50 PUSH AX ;字符参数b入栈 1442:0219 B86100 MOV AX,0061 1442:021C 50 PUSH AX ;字符参数a入栈 1442:021D B80200 MOV AX,0002 1442:0220 50 PUSH AX ;字符属性参数入栈 1442:0221 B80800 MOV AX,0008 1442:0224 50 PUSH AX ;字符数量参数入栈 1442:0225 E80500 CALL 022D ;调用show_char函数,函数的偏移地址为0228+0005=022D.同时IP入栈。 1442:0228 83C414 ADD SP,+14 ;add sp,14h,该指令的含义是回退十次入栈,即sp指向第十一次入栈。此时_SP指向main函数刚刚开始时 ;的_BP入栈使下一步_BP出栈正确。 1442:022B 5D POP BP 1442:022C C3 RET ;main函数结束,所有参数出栈。 1442:022D 55 PUSH BP ;show_char函数开始,main函数的参数基址入栈。 1442:022E 8BEC MOV BP,SP 1442:0230 56 PUSH SI ;_SI入栈 1442:0231 33F6 XOR SI,SI ;_SI清零,本函数只有一个参数整型参数a,用_SI寄存器保存。此命令相当于a=0. 1442:0233 EB49 JMP 027E ;跳转,偏移地址为235+49=27E,判断a != n。 1442:0235 8BDD MOV BX,BP ;a != n 为真。执行"*(char far *)(0xb8000000 + 160 * 12 + 80 + a + a) = *(int *)(_BP + 8 + a + a);语句" ;该赋值表达式从右向左执行。先计算*(int *)(_BP + 8 + a + a)的值。_BP + 8的含义是栈基址指针寄 ;存器回退四次入栈到第五次入栈。最近第一次入栈是本函数的push bp,最近的第二次入栈是main函数 ;中的call使IP入栈。最近第三次入栈是main函数的字符数量8入栈,最近第四次入栈是字符属性2入栈, ;最近第五次入栈是字符'a'入栈。故,_BP + 8使_BP指向字符'a',"+ a + a"的含义是根据a 的变化, ;*(int *)(_BP + 8 + a + a)可获得不同的参数。 1442:0237 03DE ADD BX,SI 1442:0239 03DE ADD BX,SI 1442:023B 83C308 ADD BX,+08 1442:023E 8A07 MOV AL,[BX] ;mov al,ds:[bx](c0s.obj在初始化环境的时候将DS=ES=SS.故ds:[bx] = ss:[bx]也是栈中的内容。) ;该命令将取得的字符参数置_AL中。 1442:0240 50 PUSH AX ;将获得的main函数的参数在本函数中入栈。赋值表达式右侧计算完毕。 1442:0241 8BC6 MOV AX,SI ;计算赋值表达式左侧。*(char far *)(0xb8000000 + 160 * 12 + 80 + a + a)因为0xb8000000为双字, ;a值与之相加也需要扩展为双字。 1442:0243 99 CWD 1442:0244 52 PUSH DX 1442:0245 50 PUSH AX 1442:0246 8BC6 MOV AX,SI 1442:0248 99 CWD 1442:0249 5B POP BX 1442:024A 59 POP CX 1442:024B 03D8 ADD BX,AX 1442:024D 13CA ADC CX,DX 1442:024F 81C3D007 ADD BX,07D0 ;偏移地址 1442:0253 81D100B8 ADC CX,B800 ;段地址 1442:0257 8EC1 MOV ES,CX 1442:0259 58 POP AX ;右侧表达式的值出栈。 1442:025A 26 ES: 1442:025B 8807 MOV [BX],AL 1442:025D 8A4606 MOV AL,[BP+06] ;*(char far *)(0xb8000000 + 160 * 12 + 81 + a + a) = color;右侧表达式的值置_AL中。 1442:0260 50 PUSH AX ;该右侧值保存。 1442:0261 8BC6 MOV AX,SI ;求左侧表达式的值。 1442:0263 99 CWD 1442:0264 52 PUSH DX 1442:0265 50 PUSH AX 1442:0266 8BC6 MOV AX,SI 1442:0268 99 CWD 1442:0269 5B POP BX 1442:026A 59 POP CX 1442:026B 03D8 ADD BX,AX 1442:026D 13CA ADC CX,DX 1442:026F 81C3D107 ADD BX,07D1 1442:0273 81D100B8 ADC CX,B800 1442:0277 8EC1 MOV ES,CX 1442:0279 58 POP AX 1442:027A 26 ES: 1442:027B 8807 MOV [BX],AL 1442:027D 46 INC SI ;对应a++,下一条指令做a != n 的判断。 1442:027E 3B7604 CMP SI,[BP+04] ;_SI即为本函数的整型参数a。[_BP+04]表示回退到最近两个入栈指令之后即指向最近的第三次入栈内容。 ;_BP的值是在1442:022E处的指令确定的,该指令最近的第一次入栈操作是push bp,最近的第二次入栈操 ;作是call指令的IP入栈。最近的第三次入栈是:mov ax,0008 push ax。入栈的是作为主调函数main的 ;最后一次入栈参数。这个参数是n。 1442:0281 75B2 JNZ 0235 ;a != n则跳转到偏移地址0283+b2=0235处执行。 1442:0283 5E POP SI 1442:0284 5D POP BP 1442:0285 C3 RET */
相关文章推荐
- 第二周项目-c语言中函数参数传递的三种方式
- C语言和JAVA一样,函数参数传递方式都为值传递方式
- C语言:函数参数传递的三种方式
- [C]C语言中函数参数传递的三种方式(x,*x,&x)
- C语言中函数参数传递的三种方式
- C语言中函数参数传递的三种方式
- 项目1-C语言中函数参数传递的三种方式
- C语言中函数的使用小记——掌握函数参数的传递方式
- C语言中多维数组的常见动态分配方式及其在函数参数传递时的应用
- 第二周项目-c语言中函数参数传递的三种方式
- 第二周项目1 C/C++语言中函数参数传递的三种方式--传值方式
- C/C++:函数参数传递方式(转)
- 函数参数传递方式:传值和传地址的问题
- C语言的3种参数传递方式
- c语言 函数 用指针传递参数 问题
- c语言 函数 用指针传递参数 问题
- Delphi过程函数传递参数的几种方式
- 第二周 C/C++语言中函数参数函数传递的三种方式
- 第二周 项目1 C/C++语言中函数参数传递的三种方式
- 第二周项目1 - C/C++语言中函数参数传递的三种方式