将小端序转换为大端序

28

我只是想问一下,我将小端存储转换成大端的方法是否正确,只是为了确保我理解了它们之间的区别。

我有一个以小端存储的数字,以下是该数字的二进制和十六进制表示:

‭0001 0010 0011 0100 0101 0110 0111 1000‬

‭12345678‬

按照大端字节序的格式,我认为字节应该被交换,像这样:

1000 0111 0110 0101 0100 0011 0010 0001

‭87654321

这正确吗?

此外,以下代码尝试进行此操作,但失败了。是否有明显的问题或者我能优化一些内容?如果此代码不适用于此转换,请说明原因并展示执行相同转换的更好方法。

uint32_t num = 0x12345678;
uint32_t b0,b1,b2,b3,b4,b5,b6,b7;
uint32_t res = 0;

b0 = (num & 0xf) << 28;
b1 = (num & 0xf0) << 24;
b2 = (num & 0xf00) << 20;
b3 = (num & 0xf000) << 16;
b4 = (num & 0xf0000) << 12;
b5 = (num & 0xf00000) << 8;
b6 = (num & 0xf000000) << 4;
b7 = (num & 0xf0000000) << 4;

res = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7;

printf("%d\n", res);

2
你可以使用更好的示例位模式,例如“0001 0010 0011 0100 0101 0110 0111 1000”。 - chux - Reinstate Monica
8
你的代码是基于四位(4-bit)的二进制数据而非八位(8-bit)的字节数据。它将32位值的各个四位进行颠倒排列。我认为你要使用基于字节的64位数值处理。此外,由于移位操作不是旋转操作,所以它们无法正常工作。因此,你将失去“超出末尾”的位数。另外,为了让代码更整洁,可以考虑使用数组而不是离散的b1,b2等变量。 - lurker
1
我正在根据以下任务进行操作:“将由十六进制表示法(st uv wx yz)表示的32位数值记录在四字节字段中,如(st uv wx yz)所示。”那么,如果我使用8位(1字节)而不是32位,它会起作用吗? - JeckyPorter
是的,这是一个32位的示例。可能是我的错误,我拿了64位而不是32位。但它肯定应该是32位的。 - JeckyPorter
3
不要自己进行转换,大多数平台都提供了处理此类操作的函数:htobe32htonl等。如果需要可移植性,请使用类似这样的头文件。 - legends2k
显示剩余2条评论
16个回答

2
#include <stdio.h>
#include <inttypes.h>

uint32_t le_to_be(uint32_t num) {
    uint8_t b[4] = {0};
    *(uint32_t*)b = num;
    uint8_t tmp = 0;
    tmp = b[0];
    b[0] = b[3];
    b[3] = tmp;
    tmp = b[1];
    b[1] = b[2];
    b[2] = tmp;
    return *(uint32_t*)b;
}

int main()
{
    printf("big endian value is %x\n", le_to_be(0xabcdef98));
    return 0;
}

这确实是回答这个非常老的问题的另一种方式。可能不是最有效的方法,但在可能的答案中值得一提。如果我可以提出改进建议,您可以在代码之外添加一些文本以解释它的作用,并解释它与其他答案的差异(例如,它将32位整数视为4字节的数组,并对该数组进行一些交换)。 - chrslg

0
#include<stdio.h>
int main(){
        int var = 0X12345678;
        var =  ((0X000000FF & var)<<24)|
               ((0X0000FF00 & var)<<8) |
               ((0X00FF0000 & var)>>8) |
               ((0XFF000000 & var)>>24);
        printf("%x",var);

}

0

这是我写的一个小函数,它工作得相当不错,可能不能适用于每台机器或单个CPU指令速度快,但应该适用于大多数情况。它可以处理长达32字节(256位)的数字,并且适用于大端和小端交换。这个函数最好的部分是你可以将它指向从线上传输过来或要传输的字节数组,并在转换之前内联交换字节。

#include <stdio.h>
#include <string.h>

void byteSwap(char**,int);

int main() {

    //32 bit
    int test32 = 0x12345678;
    printf("\n BigEndian = 0x%X\n",test32);

    char* pTest32 = (char*) &test32;

    //convert to little endian
    byteSwap((char**)&pTest32, 4);
    printf("\n LittleEndian = 0x%X\n", test32);

    //64 bit
    long int test64 = 0x1234567891234567LL;
    printf("\n BigEndian = 0x%lx\n",test64);

    char* pTest64 = (char*) &test64;

    //convert to little endian
    byteSwap((char**)&pTest64,8);
    printf("\n LittleEndian = 0x%lx\n",test64);

    //back to big endian
    byteSwap((char**)&pTest64,8);
    printf("\n BigEndian = 0x%lx\n",test64);

    return 0;
}


void byteSwap(char** src,int size) {
    int x = 0;
    char b[32];
    while(size-- >= 0) { b[x++] = (*src)[size]; };
    memcpy(*src,&b,x);
}

输出:

$gcc -o main *.c -lm
$main

 BigEndian = 0x12345678

 LittleEndian = 0x78563412

 BigEndian = 0x1234567891234567

 LittleEndian = 0x6745239178563412

 BigEndian = 0x1234567891234567

0

您可以使用库函数。它们归结为汇编语言,但如果您愿意尝试C语言的替代实现,这里有一些(假设int为32位):

void byte_swap16(unsigned short int *pVal16) {

//#define method_one 1
// #define method_two 1
#define method_three 1
#ifdef method_one
    unsigned char *pByte;

    pByte = (unsigned char *) pVal16;
    *pVal16 = (pByte[0] << 8) | pByte[1];
#endif

#ifdef method_two
    unsigned char *pByte0;
    unsigned char *pByte1;

    pByte0 = (unsigned char *) pVal16;
    pByte1 = pByte0 + 1;
    *pByte0 = *pByte0 ^ *pByte1;
    *pByte1 = *pByte0 ^ *pByte1;
    *pByte0 = *pByte0 ^ *pByte1;
#endif

#ifdef method_three
    unsigned char *pByte;

    pByte = (unsigned char *) pVal16;
    pByte[0] = pByte[0] ^ pByte[1];
    pByte[1] = pByte[0] ^ pByte[1];
    pByte[0] = pByte[0] ^ pByte[1];
#endif


}



void byte_swap32(unsigned int *pVal32) {

#ifdef method_one
    unsigned char *pByte;

    // 0x1234 5678 --> 0x7856 3412  
    pByte = (unsigned char *) pVal32;
    *pVal32 = ( pByte[0] << 24 ) | (pByte[1] << 16) | (pByte[2] << 8) | ( pByte[3] );
#endif

#if defined(method_two) || defined (method_three)
    unsigned char *pByte;

    pByte = (unsigned char *) pVal32;
    // move lsb to msb
    pByte[0] = pByte[0] ^ pByte[3];
    pByte[3] = pByte[0] ^ pByte[3];
    pByte[0] = pByte[0] ^ pByte[3];
    // move lsb to msb
    pByte[1] = pByte[1] ^ pByte[2];
    pByte[2] = pByte[1] ^ pByte[2];
    pByte[1] = pByte[1] ^ pByte[2];
#endif
}

使用方法如下:

unsigned short int u16Val = 0x1234;
byte_swap16(&u16Val);
unsigned int u32Val = 0x12345678;
byte_swap32(&u32Val);

0

以下程序将产生所需的结果:

#include <stdio.h>
 
unsigned int Little_To_Big_Endian(unsigned int num);
 
int main( )
{
    int num = 0x11223344 ;
    
    printf("\n Little_Endian = 0x%X\n",num);
    
    printf("\n Big_Endian    = 0x%X\n",Little_To_Big_Endian(num));
 
}
 
unsigned int Little_To_Big_Endian(unsigned int num)
{
    return (((num >> 24) & 0x000000ff) | ((num >> 8) & 0x0000ff00) | ((num << 8) & 0x00ff0000) | ((num << 24) & 0xff000000));
}

还可以使用以下函数:

    unsigned int Little_To_Big_Endian(unsigned int num)
    {
        return (((num & 0x000000ff) << 24) | ((num & 0x0000ff00) << 8 ) | ((num & 0x00ff0000) >> 8) | ((num & 0xff000000) >> 24 ));
    }

0

以下是另一种对我有用的方法

convertLittleEndianByteArrayToBigEndianByteArray (byte littlendianByte[], byte bigEndianByte[], int ArraySize){
    int i =0;

    for(i =0;i<ArraySize;i++){
      bigEndianByte[i] = (littlendianByte[ArraySize-i-1] << 7 & 0x80) | (littlendianByte[ArraySize-i-1] << 5 & 0x40) |
                            (littlendianByte[ArraySize-i-1] << 3 & 0x20) | (littlendianByte[ArraySize-i-1] << 1 & 0x10) |
                            (littlendianByte[ArraySize-i-1] >>1 & 0x08) | (littlendianByte[ArraySize-i-1] >> 3 & 0x04) |
                            (littlendianByte[ArraySize-i-1] >>5 & 0x02) | (littlendianByte[ArraySize-i-1] >> 7 & 0x01) ;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接