阿杰 发表于 2010-7-14 21:49:47

C中内嵌汇编进行字节序转换

前两天处理从网络上采集的数据,涉及到了对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;
}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

upring 发表于 2015-9-28 08:52:38

感谢阿杰普及科普知识
页: [1]
查看完整版本: C中内嵌汇编进行字节序转换