首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

C语言中嵌入汇编,终究有何意义

2012-09-24 
C语言中嵌入汇编,究竟有何意义?我实在想不透,这种行为的意义,难道仅仅是为了快吗?另外,汇编语言依赖于特定

C语言中嵌入汇编,究竟有何意义?
我实在想不透,这种行为的意义,难道仅仅是为了快吗?

另外,汇编语言依赖于特定的机器,在C语言中嵌入的汇编语言,会不会出现移植性的问题?



[解决办法]
比如可以直接可以操作寄存器的值
会出现移植性的问题
[解决办法]
这样加快操作速度。。看你移植的对象了!!
[解决办法]
在C语言中嵌入的汇编语言,会不会出现移植性的问题?肯定会呀。
使用嵌入汇编,主要两个目的:一是为了控制方便(比如生成位置无关的代码、使用特权指令、使用特定架构的指令实现算法等等),其次才是提高性能。

[解决办法]

探讨

引用:
比如可以直接可以操作寄存器的值
会出现移植性的问题

请教agoago_2009

通常的c代码。在翻译成汇编的时候,是不是基本上都用到了那些寄存器?——比如int a=b+c这种——如果我们在嵌入的汇编代码中直接操作寄存器的值,会不会篡改了原本程序中保存在寄存器中的数据?我的意思是,就像非法访问内存那种情况差不多……当然内存和寄存器是无关的……

[解决办法]
探讨

引用:
在C语言中嵌入的汇编语言,会不会出现移植性的问题?肯定会呀。
使用嵌入汇编,主要两个目的:一是为了控制方便(比如生成位置无关的代码、使用特权指令、使用特定架构的指令实现算法等等),其次才是提高性能。

唔……控制方便……
可我感觉汇编代码太繁冗
高级语言一行能表达的东西,汇编需要好多行好多行……

[解决办法]
有些东西只有用汇编才可以,比如溢出标志,另外在对效率很在乎的地方(如内核等),也会用到很多用来提高效率
[解决办法]
探讨

引用:
比如可以直接可以操作寄存器的值
会出现移植性的问题

请教agoago_2009

通常的c代码。在翻译成汇编的时候,是不是基本上都用到了那些寄存器?——比如int a=b+c这种——如果我们在嵌入的汇编代码中直接操作寄存器的值,会不会篡改了原本程序中保存在寄存器中的数据?我的意思是,就像非法访问内存那种情况差不多……当然内存和寄存器是无关的……

[解决办法]
如果函数工具一类的钢筋混凝土不够你来建造一座坚实的大楼 你可以用汇编纳米原子来填充
[解决办法]
CSDN之前(http://topic.csdn.net/u/20100413/20/87aa7378-cd9f-44ad-90ae-4201a3680b71.html)已经有讨论过嵌入汇编的问题,可以好好参考一下。

基本上吵嚷者汇编效率高出C许多的都是没用过汇编的(典型语录——要效率你用汇编啊)……原因很简单,一般水平的家伙写汇编就别说逻辑上跑赢C/C++的代码优化了,就在指令集这块——教材上的386级别的指令也完全比不上最新的intel指令集,现在有些牛逼的SSE指令抵得上一个小型的C函数了。

VS2008可以直接认得SSE4指令集.

类似的,VS2005支持到SSE3.

我觉得,要内嵌汇编,不用SSE3~SSE4就没有价值,而能跑赢C/C++编译器优化的专业汇编选手也太少了,因此我见到喜欢内嵌汇编的,总感觉在装B……


又见到一篇欠扁的文章,该“大牛”竟然在32位C语言程序里内嵌8086汇编以“加强效率”——mov ax,bx
[解决办法]
探讨

引用:
在C语言中嵌入的汇编语言,会不会出现移植性的问题?肯定会呀。
使用嵌入汇编,主要两个目的:一是为了控制方便(比如生成位置无关的代码、使用特权指令、使用特定架构的指令实现算法等等),其次才是提高性能。

唔……控制方便……
可我感觉汇编代码太繁冗
高级语言一行能表达的东西,汇编需要好多行好多行……

[解决办法]
有些地方需要控制寄存器。
[解决办法]
看看汇编的作用吧:
C/C++ code
//=====================================================================================/*                 CPUID指令是intel IA32架构下获得CPU信息的汇编指令,                   可以得到CPU类型,型号,制造商信息,商标信息,序列号,                   缓存等一系列CPU相关的东西。*/#include <windows.h>#include <iostream>#include <string>using namespace std;//用来存储eax,ebx,ecx,edx四个寄存器的信息DWORD deax;DWORD debx;DWORD decx;DWORD dedx;void ExeCPUID(DWORD veax)  //初始化CPU{__asm{    mov eax,veax    cpuid    mov deax,eax    mov debx,ebx    mov decx,ecx    mov dedx,edx}}/*    在Intel Pentium以上级别的CPU中,有一个称为“时间戳(Time Stamp)”的部件,    它以64位无符号整型数的格式,记录了自CPU上电以来所经过的时钟周期数。    由于目前的CPU主频都非常高,因此这个部件可以达到纳秒级的计时精度。    这个精确性是上述两种方法所无法比拟的。    在Pentium以上的CPU中,提供了一条机器指令RDTSC(Read Time Stamp Counter)    来读取这个时间戳的数字,并将其保存在EDX:EAX寄存器对中*/long GetCPUFreq()       //获取CPU频率,单位: MHZ{    int start,over;    _asm     {        RDTSC        mov start,eax    }    Sleep(50);    _asm     {        RDTSC        mov over,eax    }    return (over-start)/50000;}/*   把eax = 0作为输入参数,可以得到CPU的制造商信息。     cpuid指令执行以后,会返回一个12字符的制造商信息,     前四个字符的ASC码按低位到高位放在ebx,中间四个放在edx,最后四个字符放在ecx。*/string GetManID()   //获取制造商信息{    char ID[25];            memset(ID,0,sizeof(ID));        ExeCPUID(0);          //初始化    memcpy(ID+0,&debx,4); //制造商信息复制到数组    memcpy(ID+4,&dedx,4);    memcpy(ID+8,&decx,4);        return string(ID);}/*  在我的电脑上点击右键,选择属性,可以在窗口的下面看到一条CPU的信息,    这就是CPU的商标字符串。CPU的商标字符串也是通过cpuid得到的。    由于商标的字符串很长(48个字符),所以不能在一次cpuid指令执行时全部得到,    所以intel把它分成了3个操作,eax的输入参数分别是0x80000002,0x80000003,0x80000004,    每次返回的16个字符,按照从低位到高位的顺序依次放在eax, ebx, ecx, edx。    因此,可以用循环的方式,每次执行完以后保存结果,然后执行下一次cpuid。*/string GetCPUType(){    const DWORD id = 0x80000002; //从0x80000002开始,到0x80000004结束    char CPUType[49];//用来存储CPU型号信息    memset(CPUType,0,sizeof(CPUType));//初始化数组        for(DWORD t = 0 ; t < 3 ; t++ )    {        ExeCPUID(id+t);        //每次循环结束,保存信息到数组        memcpy(CPUType+16*t+ 0,&deax,4);        memcpy(CPUType+16*t+ 4,&debx,4);        memcpy(CPUType+16*t+ 8,&decx,4);        memcpy(CPUType+16*t+12,&dedx,4);    }        return string(CPUType);}void main() {     cout<<"本机CPU信息如下:"<<endl;    cout<<"CPU 主 频: "<<GetCPUFreq()<<" MHZ"<<endl;    cout<<"CPU 制造商: "<<GetManID()<<endl;    cout<<"CPU 型 号: "<<GetCPUType()<<endl;    cin.get();} 


[解决办法]
比如

C/C++ code
//有符号整形a和b,如何判断a+b是否溢出#include <stdio.h>int ifo_add(int a,int b) {    __asm {        mov eax,a        add eax,b        jo  overflowed        xor eax,eax        jmp no_overflowedoverflowed:        mov eax,1no_overflowed:    }}int main() {    int a,b;    a=          1;b= 2;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));    a=         -1;b=-2;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));    a= 2147483647;b= 1;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));    a=-2147483647;b=-1;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));    a=-2147483647;b=-2;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));}//          1+( 2) 0//         -1+(-2) 0// 2147483647+( 1) 1//-2147483647+(-1) 0//-2147483647+(-2) 1
[解决办法]
_asm 和 __asm 有啥区别
[解决办法]
1. 不同“架构”的cpu,汇编不同
2. 为了“快”,而且有些功能 “高级”语言不提供
3. compiler 手册会提供一定的嵌入格式,规避了“污染”其他程序中的重要数据的风险--比如先 push stack...
[解决办法]
探讨

CSDN之前(http://topic.csdn.net/u/20100413/20/87aa7378-cd9f-44ad-90ae-4201a3680b71.html)已经有讨论过嵌入汇编的问题,可以好好参考一下。

基本上吵嚷者汇编效率高出C许多的都是没用过汇编的(典型语录——要效率你用汇编啊)……原因很简单,一般水平的家伙写汇编就别说逻辑上跑赢C/C++的代码优化了,就在指令集这块——……

[解决办法]
探讨

引用:
这个你有个理解误区,你的c语言其实也可以翻译成了汇编语言,
C和汇编都是面向过程的语言,
比如你上面的代码是用C写的,它已经执行完了,然后你后面的代码是汇编语言,它继续执行,
部存在篡改问题。

呃……我的意思是,寄存器里会不会存放一些重要的东西?比如,在windows系统中,同时运行的进程可以多达几十个,可能这些进程也有些数据在寄存器里存放了那么一会,而单……

[解决办法]
一個合理的程序,應該是程序的主體用C來完成,而對時間和效率敏感的部分用ASM完成。因此,個人建議將某些重要的子程序用ASM封裝成C代碼的形式,如此即可兼顧可讀性和效率
[解决办法]
有些需要处理寄存器需要使用汇编,
[解决办法]
探讨
嗯嗯,感谢各路高手的指导,我还剩一个问题:嵌入汇编会不会“污染”其他程序中的重要数据?

就这个意思:

寄存器里会不会存放一些重要的东西?比如,在windows系统中,同时运行的进程可以多达几十个,可能这些进程也有些数据在寄存器里存放了那么一会,而单核系统下windows各个进程抢占cpu,会不会出现这种情况:前一个进程的数据放在寄存器中还没取出,我们写的嵌入汇编的c语言程序恰好改了该寄……

[解决办法]
但是 操作系统如果管理的不好,也会出现你说的问题。
[解决办法]
谁说手写的汇编代码跑不赢编译器。看看我们的测试结果。

千分求汇编语言优化 UInt96x96To192(...)
 
x86上128位二进制乘法最快速算法征解

二进制32位整数快速平方根

[解决办法]
探讨
嗯嗯,感谢各路高手的指导,我还剩一个问题:嵌入汇编会不会“污染”其他程序中的重要数据?

就这个意思:

寄存器里会不会存放一些重要的东西?比如,在windows系统中,同时运行的进程可以多达几十个,可能这些进程也有些数据在寄存器里存放了那么一会,而单核系统下windows各个进程抢占cpu,会不会出现这种情况:前一个进程的数据放在寄存器中还没取出,我们写的嵌入汇编的c语言程序恰好改了该寄……

[解决办法]
探讨
嗯嗯,感谢各路高手的指导,我还剩一个问题:嵌入汇编会不会“污染”其他程序中的重要数据?

就这个意思:

寄存器里会不会存放一些重要的东西?比如,在windows系统中,同时运行的进程可以多达几十个,可能这些进程也有些数据在寄存器里存放了那么一会,而单核系统下windows各个进程抢占cpu,会不会出现这种情况:前一个进程的数据放在寄存器中还没取出,我们写的嵌入汇编的c语言程序恰好改了该寄……

[解决办法]
汇编可以让你精确控制,如排除操作系统的保护问题,你还可以指定变量的存放地址,这就是精确控制的特点之一。
虽然汇编对硬件有移植性问题,但是只要你用得好,其核心能力强,稳定性好,可控性好,而且同样条件下,代码效率高。
一般么,汇编用来写一些关键的核心程序,以确保精确控制和稳定性。


[解决办法]
汇编一个用途是针对不同的CPU做优化,可想而知是不能移植的,不过一般用宏定义来区分,比如:
#if HAVE_AMD3DNOW
__asm__ volatile("femms");
#elif HAVE_MMX
__asm__ volatile("emms");
#endif

可以看ffmpeg代码,里面用到了大量的汇编。
[解决办法]

探讨

引用:
嗯嗯,感谢各路高手的指导,我还剩一个问题:嵌入汇编会不会“污染”其他程序中的重要数据?

就这个意思:

寄存器里会不会存放一些重要的东西?比如,在windows系统中,同时运行的进程可以多达几十个,可能这些进程也有些数据在寄存器里存放了那么一会,而单核系统下windows各个进程抢占cpu,会不会出现这种情况:前一个进程的数据放在寄存器中还没取出,我们写的……

[解决办法]
更接近底层了,更好控制
[解决办法]
探讨
嗯嗯,感谢各路高手的指导,我还剩一个问题:嵌入汇编会不会“污染”其他程序中的重要数据?

就这个意思:

寄存器里会不会存放一些重要的东西?比如,在windows系统中,同时运行的进程可以多达几十个,可能这些进程也有些数据在寄存器里存放了那么一会,而单核系统下windows各个进程抢占cpu,会不会出现这种情况:前一个进程的数据放在寄存器中还没取出,我们写的嵌入汇编的c语言程序恰好改了该寄……

[解决办法]
比如程序需要的功能C语言没有该功能,自己想想吧
[解决办法]
小声回复下,arm里的c内嵌汇编是会改变寄存器r0~r3的值,内嵌完可加上改变了哪个寄存器的值,然后c产生相应的汇编时会回避这个寄存器,用没被用过的。不知道这么说对楼主有帮助么?
[解决办法]
假设一个CPU有四个核0 1 2 3.
那么同时运行的task最多只有4个。而每个cpu都有自己的寄存器组。所以说你只用考虑一个cpu上的寄存器。
task被切换出去的时候会保存其切换出去之前时刻的寄存器信息到task的结构体(类似)中,等它再次运行的时候再恢复这些寄存器。
因此,像你说的修改寄存器是否影响其他进程的情况不存在。能影响的只有当前task所在的上下文的寄存器。
如果你在嵌入式汇编中要修改某个寄存器的值,那么先保存然后用完恢复即可。
当然,不要随意修改pc的值。
探讨

引用:
这个你有个理解误区,你的c语言其实也可以翻译成了汇编语言,
C和汇编都是面向过程的语言,
比如你上面的代码是用C写的,它已经执行完了,然后你后面的代码是汇编语言,它继续执行,
部存在篡改问题。

呃……我的意思是,寄存器里会不会存放一些重要的东西?比如,在windows系统中,同时运行的进程可以多达几十个,可能这些进程也有些数据在寄存器里存放了那么一会,而单……

热点排行