汇编中调用C中的函数,函数名前加下划线“_”

   之前见过这种用法,但是不太清楚为什么,就以为是约定俗成,其实也算是约定俗成,这样做的目的是为了防止符号名冲突,因为在一个程序中往往是包含汇编和C文件的,汇编用于启动部分,C文件用于应用程序,最终通过编译器实现编译,对于编译器来说,汇编和C是一视同仁的,那么就会有个问题,如果在汇编和C文件中使用了同一个名字,这是很可能出现的,毕竟汇编相当于机器码也算是稍微高级的语言,在定义子程序或函数时,也是可以用英文拼写的,而C文件中,更会习惯用英文拼写。

    所以为了防止类似的符号名冲突,UNIX下的C语言就规定,C语言的源代码文件中的所有全局变量和函数经过编译后,相应的符号名前面会自动的加上下划线“_”。这样做的好处,就是方便是程序开发人员,不用太小心翼翼的起名,避免了与汇编文件中的符号名的冲突。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代 码 风 格(1) 随着程序功能的增和版本的提高,程序越来越复杂,源文件也越来越多,风格规范的源程序会对软件的升级、修改和维护带来极大的方便,要想开发一个成熟的软件产品,必须在编写源程序的时候就有条不紊,细致严谨。 在编程,在程序排版、注释、命名和可读性等问题上都有一定的规范,虽然编写可读性良好的代码并不是必然的要求(世界上还有难懂代码比赛,看谁的代码最不好读懂!),但好的代码风格实际上是为自己将来维护和使用这些代码节省时间。本节就是对汇编语言代码风格的建议。 变量和函数的命名 1. 匈牙利表示法 匈牙利表示法主要用在变量和子程序的命名,这是现在大部分程序员都在使用的命名约定。“匈牙利表示法”这个奇怪的名字是为了纪念匈牙利籍的Microsoft程序员Charles Simonyi,他首先使用了这种命名方法。 匈牙利表示法用连在一起的几个部分来命名一个变量,格式是类型前缀上变量说明,类型用小写字母表示,如用h表示句柄,用dw表示double word,用sz表示以0结尾的字符串等,说明则用首字母大写的几个英文单词组成,如TimeCounter,NextPoint等,可以令人一眼看出变量的含义来,在汇编语言常用的类型前缀有: b 表示byte w 表示word dw 表示dword h 表示句柄 lp 表示指针 sz 表示以0结尾的字符串 lpsz 表示指向0结尾的字符串的指针 f 表示浮点数 st 表示一个数据结构 这样一来,变量的意思就很好理解: hWinMain 主窗口的句柄 dwTimeCount 时间计数器,以双字定义 szWelcome 欢迎信息字符串,以0结尾 lpBuffer 指向缓冲区的指针 stWndClass WNDCLASS结构 … 很明显,这些变量名比count1,abc,commandlinebuffer和FILEFLAG之类的命名要易于理解。由于匈牙利表示法既描述了变量的类型,又描述了变量的作用,所以能帮助程序员及早发现变量的使用错误,如把一个数值当指针来使用引发的内存页错误等。 对于函数名,由于不会返回多种类型的数值,所以命名时一般不再用类型开头,但名称还是用表示用途的单词组成,每个单词的首字母大写。Windows API是这种命名方式的绝好例子,当人们看到ShowWindow,GetWindowText,DeleteFile和GetCommandLine之类的API函数名称时,恐怕不用查手册,就能知道它们是做什么用的。比起int 21h/09h和int 13h/02h之类的调用,好处是不必多讲的。 2. 对匈牙利表示法的补充 使用匈牙利表示法已经基本上解决了命名的可读性问题,但相对于其他高级语言,汇编语言有语法上的特殊性,考虑下面这些汇编语言特有的问题: ● 对局部变量的地址引用要用lea指令或用addr伪操作,全局变量要用offset;对局部变量的使用要特别注意初始化问题。如何在定义区分全局变量、局部变量和参数? ● 汇编的源代码占用的行数比较多,代码行数很容易膨胀,程序规模大了如何分清一个函数是系统的API还是本程序内部的子程序? 实际上上面的这些问题都可以归纳为区分作用域的问题。为了分清变量的作用域,命名对全局变量、局部变量和参数应该有所区别,所以我们需要对匈牙利表示法做一些补充,以适应Win32汇编的特殊情况,下面的补充方法是笔者提出的,读者可以参考使用: ● 全局变量的定义使用标准的匈牙利表示法,在参数的前面下划线,在局部变量的前面@符号,这样引用的时候就能随时注意到变量的作用域。 ● 在内部子程序的名称前面下划线,以便和系统API区别。 如下面是一个求复数模的子程序,子程序名前下划线表示这是本程序内部模块,两个参数——复数的实部和虚部用_dwX和_dwY表示,间用到的局部变量@dwResult则用@号开头: _Calc proc _dwX,_dwY local @dwResult finit fild _dwX fld st(0) fmul ;i * i fild _dwY fld st(0) fmul ;j * j fadd ;i * i + j * j fsqrt ;sqrt(i * i + j * j) fistp @dwResult ;put result mov eax,@dwResult ret _Calc endp 本书所有的示范源代码采用的都是这样的命名约定。 代码的书写格式 1. 排版方式 程序的排版风格应该遵循以下规则。 首先是大小写的问题,汇编程序对于指令和寄存器的书写是不分大小写的,但小写代码比大写代码便于阅读,所以程序的指令和寄存器等要采用小写字母,而用equ伪操作符定义的常量则使用大写,变量和标号使用匈牙利表示法,大小写混合。 其次是使用Tab的问题。汇编源程序Tab的宽度一般设置为8个字符。在语法上,指令和操作数之间至少有一个空格就可以了,但指令的助记符长度是不等长的,用Tab隔开指令和操作数可以使格式对齐,便于阅读。如: xor eax,eax fistp dwNumber xchg eax,ebx 上述代码的写法就不如下面的写法整齐: xor eax,eax fistp dwNumber xchg eax, ebx 还有就是缩进格式的问题。程序的各部分采用不同的缩进,一般变量和标号的定义不缩进,指令用两个Tab缩进,遇到分支或循环伪指令再缩进一格,如: .data dwFlag dd ? .code start: mov eax,dwFlag .if dwFlag == 1 call _Function1 .else call _Function2 .endif … 合适的缩进格式可以明显地表现出程序的流程结构,也很容易发现嵌套错误,当缩进过多的时候,可以意识到嵌套过深,该改进程序结构了。
1 易语言通过国家计算机病毒防治产品检验心检验 详见帮助菜单“国家级安全检测报告” 2 修改高级表格单元格在编辑状态下未及时刷新显示内容的BUG 3 修改高级表格支持库 新增单元格列类型:#表格常量 不可编辑列表型 参见“高级表格 置列类型 ”方法 4 修改高级表格支持库 增了“边框”属性和“客户区背景颜色”属性 同时隐藏了原“客户区背景颜色 ”方法 5 修改数值计算支持库 解决大数导出整数时丢失正负号的BUG 6 修改数据库支持库个别文字说明 7 修改农历日期支持库 解决多窗口多个农历日期框共存引发的BUG 8 修改Excel2000支持库 修改“Excel工作簿 打开 ”后当前表格无法操作的BUG 修改“Excel工作簿 自动调整 ”无效的BUG 并完善了多处说明文字 9 增硬件控制 通讯类例程 方寸电话转接器 易语言5 1 相对于易语言5 0更新说明: 支持静态链接其它编程语言(如C C++ 汇编等)编译生成的静态库( LIB或 OBJ) 但仅限于COFF格式 支持cdecl和stdcall两种函数调用约定 使用说明如下:函数声明和调用方法与DLL命令一致;“库文件名”以 lib或 obj为后缀的将被视为静态库 可使用绝对路径或相对路径(相对当前源代码所在目录) 如依赖多个静态库请分别列出并以逗号分隔;“在库的对应命令名”请务必准确填写静态库公开导出的符号名称(C函数 cdecl 编译后 符号名称通常是在函数名称前下划线 );“在库的对应命令名”以@开头表示以cdecl方式调用 否则表示以默认的stdcall方式调用;各参数声明要与其定义一致 ">1 易语言通过国家计算机病毒防治产品检验心检验 详见帮助菜单“国家级安全检测报告” 2 修改高级表格单元格在编辑状态下未及时刷新显示内容的BUG 3 修改高级表格支持库 新增单元格列类型:#表格常量 不可编辑 [更多]
要在汇编语言调用C语言函数,需要按照以下步骤进行操作: 1. 定义C语言函数的原型:需要在汇编代码定义C语言函数的原型,以便编译器知道如何处理函数的参数和返回值。 2. 准备函数参数:将函数的参数保存在寄存器或堆栈,以便传递给被调用的C语言函数。 3. 调用C语言函数:使用CALL指令调用C语言函数,将执行流程转移到C语言函数执行。 4. 处理返回值:将C语言函数的返回值从寄存器或堆栈读取出来,以便在汇编代码使用。 以下是一个示例程序,演示如何在汇编语言调用C语言函数: ``` ; 汇编代码定义C语言函数的原型 extern int add(int a, int b); section .data a dd 10 b dd 20 section .text global _start _start: ; 将函数参数保存在寄存器 mov eax, dword [a] mov ebx, dword [b] ; 调用C语言函数 call add ; 处理返回值 mov ebx, eax ; 输出计算结果 mov eax, 1 mov ecx, ebx mov edx, 4 int 0x80 ; 退出程序 mov eax, 1 xor ebx, ebx int 0x80 ``` 在上面的示例程序,我们首先使用extern关键字定义了C语言函数add的原型。然后,我们在.data节定义了两个变量a和b,并在.text节将它们的值保存在寄存器eax和ebx。 接着,我们使用call指令调用C语言函数add,并将执行流程转移到C语言函数。在C语言函数执行完毕后,我们将返回值从eax寄存器读取出来,并将它保存在ebx寄存器。 最后,我们使用int 0x80指令调用系统调用输出计算结果,并使用int 0x80指令退出程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值