您的位置:首页 > 编程语言 > C语言/C++

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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: