找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 8905|回复: 1

[开源] C中内嵌汇编进行字节序转换

[复制链接]

1214

主题

352

回帖

11

精华

管理员

菜鸟

积分
93755

贡献奖关注奖人气王精英奖乐于助人勋章

发表于 2010-7-14 21:49:47 | 显示全部楼层 |阅读模式
前两天处理从网络上采集的数据,涉及到了对big-endian和litten-endian的转换,为了高效,同时正好那段
时间在看汇编与是用下面的例子来演示数据的大端与小端的区别,同时也告诉大家怎么将汇编嵌入到c中。

再对 big-endian和little-endian做个简明的解释:
little-endian    主机字节序      四个字节对称交换     低位在前高位在后
big-endian       网络字节序      四个字节顺序排列     高位在前低位在后


#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

//注意,这儿是个联合结构,主要是为了将一个长整型的数字(常见的也是4字节),以单字节的方式读取
typedef union
{
        long Long;
        char Char[sizeof(long) ];
}ByteOrder;

ByteOrder u;
ByteOrder n;

//下面的函数利用C中内嵌的汇编代码将little-endian转为big-endian,再转为little-endian
int main()
{
//        ByteOrder u;
        u.Long = 1;

        printf( "the lenght of long type data %d\n", sizeof( long ) );
        if ( u.Char[ 0 ] == 1 )
        {
                printf( "!!right-to-left\n" );
        }
        else if ( u.Char[ sizeof(long) - 1 ] == 1 )
        {
                printf( "!!left-to-right\n" );
        }

       
#if 1
        //下面的方法利用扩展asm格式:asm( "assembly code":output:input:changed regiested);
        asm( "bswap %1\n\t"
                 "movl %1, %0\n\t"
                 :"=m"(n):"a"(u) );        //"="表示只能写入操作数,可以从寄存器和内存位置给输入/出值赋值
                                //n,u不要求是全局的(当然,在这儿的确是全局的:-) )
#endif
       
        if ( n.Char[ 0 ] == 1 )
        {
                printf( "##right-to-left\n" );
        }
        else if (n.Char[ sizeof(long) - 1 ] == 1 )
        {
                printf( "##left-to-right\n" );
        }

#if 1
        //"voliatile"关键字禁止对内联汇编代码的优化
        asm volatile (
                                 "pusha\n\t"        //保存环境
                                 "movl n, %eax\n\t"        //将内存中的值放读入寄存器,n必须为全局变量,才能这样用
                                 "bswap %eax\n\t"        //对寄存器中的值进行swap操作
                                 "movl %eax, u\n\t"        //将结果保存到内存中,u必须为全局变量才能这样用
                                 "popa"                 //恢复环境
                                 );
#endif

        if ( u.Char[ 0 ] == 1 )
        {
                printf( "@@right-to-left\n" );
        }
        else if ( u.Char[ sizeof(long) - 1 ] == 1 )
        {
                printf( "@@left-to-right\n" );
        }
        return 0;
}

输出:
dongq@DongQ_Lap ~/workspace/test/byteOrder $ ./run
the lenght of long type data 4
!!right-to-left     //判断发现是little-endian
##left-to-right  //转为big-endian
@@right-to-left   //转回little-endian
【VB】QQ群:1422505加的请打上VB好友
【易语言】QQ群:9531809  或 177048
【FOXPRO】QQ群:6580324  或 33659603
【C/C++/VC】QQ群:3777552
【NiceBasic】QQ群:3703755

30

主题

693

回帖

0

精华

钻石会员

积分
2815
发表于 2015-9-28 08:52:38 | 显示全部楼层
感谢阿杰普及科普知识
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表