c语言高级编程

发布 2021-04-23 05:29:28 阅读 9698

c高级编程

责任编辑:admin 更新日期:2005-8-6

深入了解c语言(函数的参数传递和函数使用参数的方法)

tangl_99(原作)

关键字 c语言,汇编,**生成,编译器

c语言生成的**在执行效率上比其它高级语言都高。现在让我们来看看c语言生成的**具体是什么样子的。当你看完本文对于c语言的了解一定会更深一步了。

本文通过一个个实际案例程序来讲解c语言。

研究案例一

工具: turboc c v2.0,debug,masm v5.0,nasm

实例c程序:

char ch;

int e_main()

e_putchar(ch);

目标内容:c语言调用函数的方法与细节

我们使用的c编译器是16位的turboc c v2.0,它生成的是16位的**,比较简单,方便我们来研究。同时我们也需要用到dos下的debug来进行反汇编。

由于我们很多案例中的程序并不是完整的c程序,所以turboc下的tlink并不能为我们生成目标程序,所以我将使用masm中的同时里面的也可以为我们把exe文件转换成bin文件。

这个程序没有main函数,我们用e_main来代替main函数。这样我们能避开c语言对main函数进行一系列处理的**。同样,我们也用e_putchar()来代替我们平常使用的putchar().

这里"e"的意思就是"example".

没有了main函数,我们的c程序就没有了入口,所以在开始编译这段c**之前,我还得写几行简单的汇编**,通过它来作为我们程序的入口。

c程序的入口

bits 16]

global start]

extern _e_main]

start:

call _e_main

按照c语言的习惯,所以c总的名词都要自动在前面加一个"_"下划线。所以,我们在c中的e_main函数,如果要在汇编中调用,就变成了_e_main函数。这段汇编**只有一句:

call _e_main,就是调用我们在c中的e_main函数

这段**我将用nasm来进行编译。生成

nasmw -f obj -o

下面我们用turboc c来编译这段c**:

tcc -mt -c

link exe2bin

这样,我们就得到了这段c**编译出来的机器**文件(了。

下面我们用debug这个老dos的工具来对进行反汇编。

debug

n l 0

u 0 xxxx:0000 call 0003

xxxx:0003 mov ax,000b

xxxx:0006 push ax

xxxx:0007 call 0020

xxxx:000a pop cx

这里看到蓝色的**就是我们整个c程序的所生成的**了。

最开始的第一句call 0003是我们用nasm编译的所生成的**。

我们主要目标是研究蓝色的c语言的**,第一句所生成的**太简单,就是调用e_main函数。而我们的e_main函数就是蓝色**部分。

从c源程序中我们看到,我们在e_main做的就是一件事情:调用e_putchar(ch);其中ch是传给出e_putchar的参数。

mov ax,000b

000b就是我们。

的全局变量ch所在内存的地址。c语言会把所有的全局变量在另一块内存区。c**先把ch的地址传给ax,然后通过

push ax

把ax的值,也就是ch的地址压入堆栈。然后再

call 0020

而0020就是e_putchar**的地址。通过这跳语句,计算机就跳到e_putchar的**部分去执行了。我在这里并不给出e_putchar的**,因为我们这个案例只是研究c语言中如何传递参数给其它函数的,并不管e_putchar如何取参数。

下在一个案例中,我们将研究函数如何取参数。

在这里我得把call指令解释清楚,因为在下个研究函数如何取参数的部分中大家可能会迷惑。call xxxx 指令简单地或就是

push ip

jmp xxxx

它首先把当前的执行地址ip压入堆栈,然后跳转到要call的地址去。call和ret指令是配套的。ret指令等同于

pop ip

也就是回复call前的执行地址ip.

正因为这样,所以你一旦使用了call指令,你的堆栈指针sp就会自动减2.

pop cx

是每个函数调用完毕后都有的必备操作。在这里它不起任何作用。可能唯一的作用就是与call 0020前的push ax像对应。这样堆栈指针sp才能回原。

好了,简单的第一个案例研究结束了。虽然就这4跳指令,但是我们已经可以看出c语言传递参数方法了。总结起来就是通过"mov ax,参数地址"把参数的地址传到ax,然后"push ax"把参数的地址压入堆栈。

最后"call 函数地址"转向执行要调用的函数。最后调用完后,"pop cx",恢复堆栈指针sp.

研究案例二工具: turboc c v2.0,debug,masm v5.0,nasm,tasm

实例c程序:

char ch;

extern void e_putchar(char c);

int e_mainch=0x44;

e_putchar(ch实例汇编程序:

text segment byte public 'code'

dgroup group _text

assume cs:_text,ds:dgroup,ss:dgroup

public _k_putchar

k_putchar proc near

push bp

mov bp,sp

mov ah,0eh

mov bx,7h

mov al,byte ptr [bp+4]

int 10h

pop bp

ret k_putchar endp

目标内容:c语言中函数使用参数的方法这一节我们将使用tasm用汇编来写个标准的c函数。这一节的内容大家可能在很多汇编的书籍上都看到过。

讲的是c语言和汇编语言的连接方法。可能你会奇怪,我们这里已经有了masm,nasm两个汇编编译器了,为什么还要使用tasm另外一个汇编编译器。我不知道masm是否可以和我们的turboc c配合,但是tasm是肯定可以和turboc c完全配合的。

毕竟它们都是borland公司的产品,而且turboc c中用-s生成的汇编**是完全按照tasm中的语法而定的。这足以见turboc c和tasm之间"亲密的"关系了。

这个案例中我们主要并不研究c**了。而是研究那个用汇编写的c函数。

push bp

mov bp,sp

mov ah,0eh

mov bx,7h

mov al,byte ptr [bp+4]

int 10h

pop bp

ret 其中byte ptr[bp+4]就是我们传给e_putchar()的参数值。

前一个案例中我们一直。

直知道了c语言是把参数的地址压入堆栈的方式传给函数。所以在标准的c函数中,都是通过取堆栈里的值来读参数。

标准的c函数前两行都是

push bp

mov bp,sp

首先保存bp的值,然后把当前的堆栈指针传递给bp,我们访问传递给该函数的参数就是通过bp.而第一个参数值就放在bp+4的地址中,第二个参数值就放在bp+6,..这样依此对应每个参数的地址。

bp就是call调用前的ip的值。因为call执行的时候,系统会自动把当前的ip压入堆栈。关于这个前面一个案例中已经给出介绍。

别看这个c函数是用汇编语言写的,它可是个完完整整的c函数。

好了,让我们编译出来看看。

tasm tcc -mt -c

link exe2bin

好了,该是我们总结的时候了。

c语言中函数访问参数的方法就是先通过"push bp"保存bp,"mov bp,sp"把当前的堆栈指针传递给bp.第一个参数的地址就在bp+4,第二个参数的地址就在bp+6,..比如"mov ax,word ptr[bp+4]"就可以把第一个参数值传给ax 寄存器。

而需要留意的是c/c++传递参数的顺序是和其它语言相反的。c语言是把参数的地址从右到左压入堆栈,所以越后面的参数,在堆栈中的地址越靠前。

C语言高级编程

基本信息。原书名 expert c programming原出版社 prentice hall ptr作者 美 peter van der linden译者 徐波。丛书名 c和c 经典著作 出版社 人民邮电出版社 isbn 9787115171801 上架时间 2008 2 2 出版日期 2008 ...

C语言高级编程及实例剖析

第一章 内存管理。c语言对程序精心编译时,将函数中命令 语句编译成相应序列的机器指令 放在 段 将已初始化的数据,如已赋值的全局变量 静态局部变量等,放在数据段 将未初始化的数据放在bbs段内 将临时数据,如函数调用时传递的参数 局部变量 返 用时的地址等放在栈段内 而对一些动态变化的数据,如在程序...

C语言高级编程实验指导书

实验。一 熟悉开发平台 常用工具。实验要求 熟练使用该节介绍的linux命令 使用vi创建 编辑 保存文件。实验平台 pc机 ubuntu 10.04 实验步骤 一 熟悉常用命令 1.man命名查看常用命令函数的具体用法。2.cd切换目录。3.ls命令查看目录内容。4.pwd命令查看当前路径。5.u...