利用指针变量用函数实现将3个整数按从大到小的顺序输出。
本文出自 “” 博客请务必保留此出处
利用指针变量用函数实现将3个整数按从大到小的顺序输出。
本文出自 “” 博客请务必保留此出处
C代码执行效率与哪些因素有关
保障C代码执行效率的原则
在许多种情况下,可以用指针运算代替数组索引这样做常常能产生又快又短的代码。与数组索引相比指针一般能使代码速度更快,占用空间更少使用多维数组时差异更明显。下媔的代码作用是相同的但是效率不一样。
函数和宏的区别就在于宏占用了大量的空间,而函数占用了时间大家要知道的是,函数调用是要使用系统的栈来保存数据的如果编译器 里有栈检查选 项,一般在函数的头会嵌入一些汇编语句对当前栈进行检查;同时CPU也要在函数调用时保存和恢复当前的现场,进行压栈和弹栈操作所以,函數调用需要一
些CPU时间而宏不存在这个问题。宏仅仅作为预先写好的代码嵌入到当前程序不会产生函数调用,所以仅仅是占用了空间茬频繁调用同一个宏的时候,该现象尤其突出
B方法是我看到的最好的置位操作函数,是ARM公司源码的一部分在短短的三行内实现了很多功能,几乎涵盖了所有的位操作功能A方法是其变体,其中滋味还需大家仔细体会
计算机程序中最大的矛盾是空间和时间的矛盾那么,从这个角度出发逆向思维来考虑程序的效率问题我们就囿了解决问题的第1招--以空间换时间。比如说字符串的赋值:
使用的时候可以直接用指针来操作
从上面的例子可以看出,A和B的效率是不能仳的在同样的存储空间下,B直接使用指针就可以操作了而A需要调用两个字符函数才能完成。B的缺点在于灵活性没有A好在需要频繁更妀一个字符串内容的时候,A具有更好的灵活性;如果采用方法B则需要预存许多字符串,虽然占用了大量的内存但是获得了程序执行 的高效率。
如果系统的实时性要求很高内存还有一些,那我推荐你使用该招数
虽然是必杀技,但是如果轻易使用会付出惨重的代价这是因为,使鼡了嵌入汇编便限制了程序的可移植性,使程序在不同平台移植的过程中卧虎藏龙,险象环生!同时该招数也与现代软件工程的思想楿违背只有在迫不得已的情况下才可以采用。
9、确保声明和定义是静态的除非您希望从不哃的文件中调用该函数。
在同一文件函数对其他函数可见才称之为静态函数。它限制其他访问内部函数如果我们希望从外界隐藏该函數。现在我们并不需要为内部函数创建头文件其他看不到该函数。静态声明一个函数的优点包括:
(1)两个或两个以上具有相同名称的靜态函数可用于在不同的文件。
这个例子是我印象最深的一个数学用例是我的计算机啟蒙老师考我的。当时我只有小学三年级可惜我当时不知道用公式 N×(N+1)/ 2
来解决这个问题。方法E循环了100次才解决问题也就是说最少用叻100个赋值,100个判断200个加法(I和j);而方法F仅仅用了1个加法,1次乘法1次除法。效果自然不言而喻所以,现在我在编程序的时候更多嘚是动脑筋找规律,最大限度地发挥数学的威力来提高程序运行的效率
使用位操作。减少除法和取模的运算在计算机程序中数据的位昰可以操作的最小数据单位,理论上可以用"位运算"来完成所有的运算和操作一般的位操作是用来控制硬件的,或者做数据变换使用但昰,灵活的位操作可以有效地提高程序运行的效率举例如下:
在字面上好像B比A麻烦了好多,但是仔细查看产生的汇编代码就会明白,方法B调用了基本的取模函数和除法函数既有函数调用,还有很多汇编代码和寄存器参 与运算;而方法H则仅仅是几句相关的汇编代码更簡洁,效率更高当然,由于编译器的不同可能效率的差距不大,但是以我目前遇到的MS C ,ARM C 来看,效率的差距还是不小
对于以2的指数次方为"*"、"/"或"%"因子的数学运算,转化为移位运算"<< >>"通常可以提高算法效率因为乘除运算指令周期通常比移位运算大。
c语言调用函数的编程例子位运算除了可以提高运算效率外在嵌入式系统的编程中,它的另一个最典型的应用而且十分广泛地正在被使用着的是位间的与(&)、戓 (|)、非(~)操作,这跟嵌入式系统的编程特点有很大关系我们通常要对硬件寄存器进行位设置,譬如我们通过将AM186ER型80186处理器的中 断屏蔽控制寄存器的第低6位设置为0(开中断2),最通用的做法是:
而将该位设置为1的做法是:
判断该位是否为1的做法是:
运用这招需要注意嘚是因为CPU的不同而产生的问题。比如说在PC上用这招编写的程序,并在PC上调试通过在移植到一个16位机平台上的时候,可能会产生代码隱患所以只有在一定技术进阶的基础下才可以使用这招。
首先要明白CPU对各种存储器的访问速度基本上是:
对于程序代码,已经被烧录茬FLASH或ROM中我们可以让CPU直接从其中读取代码执行,但通常这不是一个好办法我们最好在系统启动后将FLASH或ROM中的目标代码拷贝入RAM中后再执行以提高取指令速度;
对于UART等设备,其内部有一定容量的接收BUFFER我们应尽量在BUFFER被占满后再向CPU提出中断。例如计算机终端在向目标机通过RS-232传递数據时不宜设置UART只接收到一个BYTE就向CPU提中断,从而无谓浪费中断处理时间;
如果对某设备能采取DMA方式读取就采用DMA读取,DMA读取方式在读取目標中包含的存储信息较大时效率较高其数据传输的基本单位是块,而所传输 的数据是从设备直接送入内存的(或者相反)DMA方式较之中斷驱动方式,减少了CPU 对外设的干预进一步提高了CPU与外设的并行操作程度。
当对一个变量频繁被读写时需要反复访问内存,从而花费大量的存取时间为此,c语言调用函数的编程例子提供了一种变量即寄存器变量。这种变量存放在CPU的寄存器中使 用时,不需要访问内存而直接从寄存器中读写,从而提高效率寄存器变量的说明符是register。对于循环次数较多的循环控制变量及循环体内反复使用 的变量均可定義为寄存器变量而循环计数是应用寄存器变量的最好候选者。
(1) 只有局部自动变量和形参才可以定义为寄存器变量因为寄存器变量属于動态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量包括:模块间全局变量、模块内全局变量、局部static变量;
(2) register是一个"建議"型关键字,意指程序建议该变量放在寄存器中但最终该变量可能因为条件不满足并未成为寄存器变量,而是被放在了存储器中但编譯器中并不报错(在C++语言中有另一个"建议"型关键字:inline)。
下面是一个采用寄存器变量的例子:
本程序循环n次i和s都被频繁使用,因此可定義为寄存器变量
保障C代码执行效率的优化方法
function函数定义並不知道函数返回值是否被使用,假如返回值从来不会被用到应该使用void来明确声明函数不返回任何值。
目的很明确:在主函数中让字符串两两进行比较如果条件满足if语句,那么就会调用swap函数调用swap时我们想要把字符串首地址传给形参,让形参来完成调换功能思路是这樣,那么我们检验一下结果:
程序没有达到我们想要的结果你觉得问题出在哪里?
我们用另外一个简单的程序来说明问题出在哪里:
这個程序我们再熟悉不过了这个程序是“单向传值调用”,即将实参的值拷贝一份传送给形参并且分配另外一个空间给形参,而调用swap函數时只是把形参的值改变了,但是并没有改变实参的值后来我们改用了“双向传址调用”方法:
同样将实参的值作一份拷贝传给形参,但拷贝的是元素的地址;同样给形参分配不同的空间但形参的空间里存放的是元素的地址。最后指针通过元素的地址访问并且修改了え素本身的值
回归我们第一个程序,我们将字符串首元素地址进行拷贝传送给形参而形参中是用一级指针变量接收,通常来说指针就昰地址也就是说我们只能调换形参值,而不能到达实参值的调换为了能到达实参值的调换,我们可以用二级指针来接收实参:
此时就能达到我们想要的结果: