Win知识 - 程序是怎样跑起来的——了解程序运行方式的必要性

简介: Win知识 - 程序是怎样跑起来的——了解程序运行方式的必要性

通过对C语言源代码和汇编语言源代码进行比较,想必大家对“程序是怎样跑起来的”又有了更深的理解。而且,从汇编语言源代码中获得的知识,在某些情况下对查找bug的原因也是有帮助的。

让我们来看个示例。代码清单10-13是更新全局变量counter的值的C语言程序。MyFunc1函数和MyFunc2函数的处理内容,都是把全局变量counter的值放大到2倍。counter*=2;指的是把counter的数值乘以2,然后再把所得结果赋值到counter的意思。这里,假设我们利用多线程处理①,同时调用了一次MyFunc1函数和MyFunc2函数。这时,全局变量counter的数值,理应变成100×2×2=400。然而,某些时候结果也可能会是200。至于为什么会出现该bug,如果没有调查过汇编语言的源代码,也就是说如果对程序的实际运行方式不了解的话,是很难找到其原因的。


代码清单10-13 两个函数更新同一个全局变量数值的C语言程序

//定义全局变量intcounter=100;//定义MyFunc1函数voidMyFunc1()    {counter=2;    }//定义MyFunc2函数voidMyFunc2()    {counter=2;    }

将代码清单10-13的counter *=2;部分转换成汇编语言源代码后,结果就如代码清单10-14所示。这里希望大家注意的是,C语言源代码中counter *=2;这一个指令的部分,在汇编语言源代码,也就是实际运行的程序中,分成了3个指令。如果只是看counter *=2;的话,就会以为counter的数值被直接扩大为了原来的2倍。然而,实际上执行的却是“把counter的数值读入eax寄存器”“将eax寄存器的数值变成原来的2倍”“把eax寄存器的数值写入counter”这3个处理。


代码清单10-14 将全局变量的值翻倍这一部分转换成汇编语言源代码的结果

moveax, dwordptr[_counter]  ; 将counter的值读入eax寄存器addeax, eax                  ; 将eax寄存器的值扩大至原来的2倍movdwordptr[_counter], eax  ; 将eax寄存器的数值存入counter中

在多线程处理中,用汇编语言记述的代码每运行1行,处理都有可能切换到其他线程(函数)中。因而,假设 MyFunc1函数在读出counter的数值100后,还未来得及将它的2倍值200写入counter时,正巧MyFunc2函数读出了counter的数值100,那么结果就会导致counter的数值变成了200(图10-8)。

image.png

图10-8 100×2×2的结果成200的过程


为了避免该bug,我们可以采用以函数或C语言源代码的行为单位来禁止线程切换的锁定方法。通过锁定,在特定范围内的处理完成之前,处理不会被切换到其他函数中。至于为什么要锁定MyFunc1函数和MyFunc2函数,大家如果不了解汇编语言源代码的话想必是不明白的吧。


现在基本上没有人用汇编语言来编写程序了。因为C语言等高级编程语言用1行就可以完成的处理,使用汇编语言的话有时就需要多行,效率很低。不过,汇编语言的经验还是很重要的。因为借助汇编语言,我们可以更好地了解计算机的机制。特别是对专业程序员来说,至少要有一次使用汇编语言的经验。


下面让我们以开车为例进行说明。没有汇编语言经验的程序员,就相当于只知道汽车的驾驶方法而不了解汽车结构的驾驶员。对这样的驾驶员来说,如果汽车出现了故障或奇怪的现象,他们就无法自己找到原因。不了解汽车结构的话,开车的时候还可能会浪费油。这样的话,作为职业驾驶员是不合格的。与此相对,有汇编语言经验的程序员,也就相当于了解计算机和程序机制的驾驶员,他们不仅能自己解决问题,还能在驾驶过程中省油。


本章的内容确实有些绕,但是对了解计算机和程序的实际运行方式来说,体验汇编语言是最有效的。如果大家会使用C语言的话,希望大家对C语言的各种语法所对应的汇编语言都一一确认一下。最好能编写一些简短的程序来进行反复的测试。笔者自身也是通过进行这些尝试才使自己的编程技能有了大幅提高的。


下一章,我们将会对I/O端口的输入输出及中断处理等用程序来控制硬件的方法进行说明,同时也会介绍一个使用汇编语言的示例程序。

Ps:注脚

① “线程”是操作系统分配给CPU的最小运行单位。源代码的一个函数就相当于一个线程。多线程处理指的是在一个程序中同时运行多个函数的意思。


目录
相关文章
|
4月前
|
Oracle 关系型数据库 Unix
程序运行时环境
程序运行时环境
|
Linux C语言
实验 线程编程-加1操作为什么会出错?【操作系统】
实验 线程编程-加1操作为什么会出错?【操作系统】
118 1
|
8月前
|
数据采集 缓存 前端开发
LabVIEW用了多线程,程序是不是会跑的更快些
LabVIEW用了多线程,程序是不是会跑的更快些
100 0
|
JSON C++ 数据格式
《C++避坑神器·二十二》VS能正常运行程序,但运行exe程序无响应解决办法
《C++避坑神器·二十二》VS能正常运行程序,但运行exe程序无响应解决办法
196 0
|
存储 自然语言处理 编译器
程序的编译与链接(C语言为例) #代码写好后到运行期间要经过怎样的过程呢?# 粗略版 #
程序的编译与链接(C语言为例) #代码写好后到运行期间要经过怎样的过程呢?# 粗略版 #
|
Java 索引 Windows
【操作系统作业】数独解决方案验证器(利用多线程解决)
【操作系统作业】数独解决方案验证器(利用多线程解决)
|
存储 编译器 C语言
Win知识 - 程序是怎样跑起来的——函数调用机制
Win知识 - 程序是怎样跑起来的——函数调用机制
114 0
Win知识 - 程序是怎样跑起来的——函数调用机制
|
存储 API C语言
Win知识 - 程序是怎样跑起来的——应用和硬件无关?
Win知识 - 程序是怎样跑起来的——应用和硬件无关?
148 0
Win知识 - 程序是怎样跑起来的——应用和硬件无关?
|
存储 C语言
Win知识 - 程序是怎样跑起来的——函数内部的处理
Win知识 - 程序是怎样跑起来的——函数内部的处理
90 0
Win知识 - 程序是怎样跑起来的——函数内部的处理
|
程序员 C语言 Windows
Win知识 - 程序是怎样跑起来的——要意识到操作系统的存在
Win知识 - 程序是怎样跑起来的——要意识到操作系统的存在
109 0
Win知识 - 程序是怎样跑起来的——要意识到操作系统的存在