Windows little endian to big endian

Problem Description:

I just want to ask if my method is correct to convert from little endian to big endian, just to make sure if I understand the difference.

I have a number which is stored in little-endian, here are the binary and hex representations of the number:

‭0001 0010 0011 0100 0101 0110 0111 1000‬

‭12345678‬

In big-endian format I believe the bytes should be swapped, like this:

1000 0111 0110 0101 0100 0011 0010 0001

‭87654321

Is this correct?

Also, the code below attempts to do this but fails. Is there anything obviously wrong or can I optimize something? If the code is bad for this conversion can you please explain why and show a better method of performing the same conversion?

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("%dn", res);

Solution – 1

I think you can use function htonl(). Network byte order is big endian.

Solution – 2

OP’s sample code is incorrect.

Endian conversion works at the bit and 8-bit byte level. Most endian issues deal with the byte level. OP’s code is doing a endian change at the 4-bit nibble level. Recommend instead:

// Swap endian (big to little) or (little to big)
uint32_t num = 9;
uint32_t b0,b1,b2,b3;
uint32_t res;

b0 = (num & 0x000000ff) << 24u;
b1 = (num & 0x0000ff00) << 8u;
b2 = (num & 0x00ff0000) >> 8u;
b3 = (num & 0xff000000) >> 24u;

res = b0 | b1 | b2 | b3;

printf("%" PRIX32 "n", res);

If performance is truly important, the particular processor would need to be known. Otherwise, leave it to the compiler.

[Edit] OP added a comment that changes things.
«32bit numerical value represented by the hexadecimal representation (st uv wx yz) shall be recorded in a four-byte field as (st uv wx yz).»

It appears in this case, the endian of the 32-bit number is unknown and the result needs to be store in memory in little endian order.

uint32_t num = 9;
uint8_t b[4];
b[0] = (uint8_t) (num >>  0u);
b[1] = (uint8_t) (num >>  8u);
b[2] = (uint8_t) (num >> 16u);
b[3] = (uint8_t) (num >> 24u);

[2016 Edit] Simplification

… The type of the result is that of the promoted left operand…. Bitwise shift operators C11 §6.5.7 3

Using a u after the shift constants (right operands) results in the same as without it.

b3 = (num & 0xff000000) >> 24u;
b[3] = (uint8_t) (num >> 24u);
// same as 
b3 = (num & 0xff000000) >> 24;
b[3] = (uint8_t) (num >> 24);

Solution – 3

“I swap each bytes right?” -> yes, to convert between little and big endian, you just give the bytes the opposite order.
But at first realize few things:

  • size of uint32_t is 32bits, which is 4 bytes, which is 8 HEX digits
  • mask 0xf retrieves the 4 least significant bits, to retrieve 8 bits, you need 0xff

so in case you want to swap the order of 4 bytes with that kind of masks, you could:

uint32_t res = 0;
b0 = (num & 0xff) << 24;        ; least significant to most significant
b1 = (num & 0xff00) << 8;       ; 2nd least sig. to 2nd most sig.
b2 = (num & 0xff0000) >> 8;     ; 2nd most sig. to 2nd least sig.
b3 = (num & 0xff000000) >> 24;  ; most sig. to least sig.
res = b0 | b1 | b2 | b3 ;

Solution – 4

One slightly different way of tackling this that can sometimes be useful is to have a union of the sixteen or thirty-two bit value and an array of chars. I’ve just been doing this when getting serial messages that come in with big endian order, yet am working on a little endian micro.

union MessageLengthUnion
{

    uint16_t asInt;
    uint8_t asChars[2];

};

Then when I get the messages in I put the first received uint8 in .asChars[1], the second in .asChars[0] then I access it as the .asInt part of the union in the rest of my program.

If you have a thirty-two bit value to store you can have the array four long.

Solution – 5

You could do this:

int x = 0x12345678;

x = ( x >> 24 ) | (( x << 8) & 0x00ff0000 )| ((x >> 8) & 0x0000ff00) | ( x << 24)  ; 

printf("value = %x", x);  // x will be printed as 0x78563412

Solution – 6

one more suggestion :

unsigned int a = 0xABCDEF23;
a = ((a&(0x0000FFFF)) << 16) | ((a&(0xFFFF0000)) >> 16);
a = ((a&(0x00FF00FF)) << 8) | ((a&(0xFF00FF00)) >>8);
printf("%0xn",a);

Solution – 7

I am assuming you are on linux

Include "byteswap.h" & Use int32_t bswap_32(int32_t argument);

It is logical view, In actual see, /usr/include/byteswap.h

Solution – 8

OP’s code is incorrect for the following reasons:

  • The swaps are being performed on a nibble (4-bit) boundary, instead of a byte (8-bit) boundary.
  • The shift-left << operations of the final four swaps are incorrect, they should be shift-right >> operations and their shift values would also need to be corrected.
  • The use of intermediary storage is unnecessary, and the code can therefore be rewritten to be more concise/recognizable. In doing so, some compilers will be able to better-optimize the code by recognizing the oft-used pattern.

Consider the following code, which efficiently converts an unsigned value:

// Swap endian (big to little) or (little to big)
uint32_t num = 0x12345678;
uint32_t res =
    ((num & 0x000000FF) << 24) |
    ((num & 0x0000FF00) << 8) |
    ((num & 0x00FF0000) >> 8) |
    ((num & 0xFF000000) >> 24);

printf("%0xn", res);

The result is represented here in both binary and hex, notice how the bytes have swapped:

‭0111 1000 0101 0110 0011 0100 0001 0010‬

78563412

Optimizing

In terms of performance, leave it to the compiler to optimize your code when possible. You should avoid unnecessary data structures like arrays for simple algorithms like this, doing so will usually cause different instruction behavior such as accessing RAM instead of using CPU registers.

Solution – 9

You can use the lib functions. They boil down to assembly, but if you are open to alternate implementations in C, here they are (assuming int is 32-bits) :

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
}

And the usage is performed like so:

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

Solution – 10

A Simple C program to convert from little to big

#include <stdio.h>

int main() {
unsigned int little=0x1234ABCD,big=0;
unsigned char tmp=0,l;

printf(" Little endian little=%xn",little);

for(l=0;l < 4;l++) 
{
    tmp=0;
    tmp = little | tmp;
    big = tmp | (big << 8);
    little = little >> 8;
}
printf(" Big endian big=%xn",big);

return 0;
}

Solution – 11

Sorry, my answer is a bit too late, but it seems nobody mentioned built-in functions to reverse byte order, which in very important in terms of performance.

Most of the modern processors are little-endian, while all network protocols are big-endian. That is history and more on that you can find on Wikipedia. But that means our processors convert between little- and big-endian millions of times while we browse the Internet.

That is why most architectures have a dedicated processor instructions to facilitate this task. For x86 architectures there is BSWAP instruction, and for ARMs there is REV. This is the most efficient way to reverse byte order.

To avoid assembly in our C code, we can use built-ins instead. For GCC there is __builtin_bswap32() function and for Visual C++ there is _byteswap_ulong(). Those function will generate just one processor instruction on most architectures.

Here is an example:

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

int main()
{
    uint32_t le = 0x12345678;
    uint32_t be = __builtin_bswap32(le);

    printf("Little-endian: 0x%" PRIx32 "n", le);
    printf("Big-endian:    0x%" PRIx32 "n", be);

    return 0;
}

Here is the output it produces:

Little-endian: 0x12345678
Big-endian:    0x78563412

And here is the disassembly (without optimization, i.e. -O0):

        uint32_t be = __builtin_bswap32(le);
   0x0000000000400535 <+15>:    mov    -0x8(%rbp),%eax
   0x0000000000400538 <+18>:    bswap  %eax
   0x000000000040053a <+20>:    mov    %eax,-0x4(%rbp)

There is just one BSWAP instruction indeed.

So, if we do care about the performance, we should use those built-in functions instead of any other method of byte reversing. Just my 2 cents.

Solution – 12

Below is an other approach that was useful for me

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) ;
    }
}

Solution – 13

Below program produce the result as needed:

#include <stdio.h>
 
unsigned int Little_To_Big_Endian(unsigned int num);
 
int main( )
{
    int num = 0x11223344 ;
    
    printf("n Little_Endian = 0x%Xn",num);
    
    printf("n Big_Endian    = 0x%Xn",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));
}

And also below function can be used:

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

Solution – 14

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

}

Solution – 15

Here is a little function I wrote that works pretty good, its probably not portable to every single machine or as fast a single cpu instruction, but should work for most. It can handle numbers up to 32 byte (256 bit) and works for both big and little endian swaps. The nicest part about this function is you can point it into a byte array coming off or going on the wire and swap the bytes inline before converting.

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

void byteSwap(char**,int);

int main() {

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

    char* pTest32 = (char*) &test32;

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

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

    char* pTest64 = (char*) &test64;

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

    //back to big endian
    byteSwap((char**)&pTest64,8);
    printf("n BigEndian = 0x%lxn",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);
}

output:

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

 BigEndian = 0x12345678

 LittleEndian = 0x78563412

 BigEndian = 0x1234567891234567

 LittleEndian = 0x6745239178563412

 BigEndian = 0x1234567891234567

Solution – 16

#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 %xn", le_to_be(0xabcdef98));
    return 0;
}

I just want to ask if my method is correct to convert from little endian to big endian, just to make sure if I understand the difference.

I have a number which is stored in little-endian, here are the binary and hex representations of the number:

‭0001 0010 0011 0100 0101 0110 0111 1000‬

‭12345678‬

In big-endian format I believe the bytes should be swapped, like this:

1000 0111 0110 0101 0100 0011 0010 0001

‭87654321

Is this correct?

Also, the code below attempts to do this but fails. Is there anything obviously wrong or can I optimize something? If the code is bad for this conversion can you please explain why and show a better method of performing the same conversion?

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);

Shaun Wilson's user avatar

Shaun Wilson

8,7273 gold badges50 silver badges48 bronze badges

asked Oct 9, 2013 at 15:13

JeckyPorter's user avatar

7

OP’s sample code is incorrect.

Endian conversion works at the bit and 8-bit byte level. Most endian issues deal with the byte level. OP’s code is doing a endian change at the 4-bit nibble level. Recommend instead:

// Swap endian (big to little) or (little to big)
uint32_t num = 9;
uint32_t b0,b1,b2,b3;
uint32_t res;

b0 = (num & 0x000000ff) << 24u;
b1 = (num & 0x0000ff00) << 8u;
b2 = (num & 0x00ff0000) >> 8u;
b3 = (num & 0xff000000) >> 24u;

res = b0 | b1 | b2 | b3;

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

If performance is truly important, the particular processor would need to be known. Otherwise, leave it to the compiler.

[Edit] OP added a comment that changes things.
«32bit numerical value represented by the hexadecimal representation (st uv wx yz) shall be recorded in a four-byte field as (st uv wx yz).»

It appears in this case, the endian of the 32-bit number is unknown and the result needs to be store in memory in little endian order.

uint32_t num = 9;
uint8_t b[4];
b[0] = (uint8_t) (num >>  0u);
b[1] = (uint8_t) (num >>  8u);
b[2] = (uint8_t) (num >> 16u);
b[3] = (uint8_t) (num >> 24u);

[2016 Edit] Simplification

… The type of the result is that of the promoted left operand…. Bitwise shift operators C11 §6.5.7 3

Using a u after the shift constants (right operands) results in the same as without it.

b3 = (num & 0xff000000) >> 24u;
b[3] = (uint8_t) (num >> 24u);
// same as 
b3 = (num & 0xff000000) >> 24;
b[3] = (uint8_t) (num >> 24);

answered Oct 9, 2013 at 15:25

chux - Reinstate Monica's user avatar

2

Sorry, my answer is a bit too late, but it seems nobody mentioned built-in functions to reverse byte order, which in very important in terms of performance.

Most of the modern processors are little-endian, while all network protocols are big-endian. That is history and more on that you can find on Wikipedia. But that means our processors convert between little- and big-endian millions of times while we browse the Internet.

That is why most architectures have a dedicated processor instructions to facilitate this task. For x86 architectures there is BSWAP instruction, and for ARMs there is REV. This is the most efficient way to reverse byte order.

To avoid assembly in our C code, we can use built-ins instead. For GCC there is __builtin_bswap32() function and for Visual C++ there is _byteswap_ulong(). Those function will generate just one processor instruction on most architectures.

Here is an example:

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

int main()
{
    uint32_t le = 0x12345678;
    uint32_t be = __builtin_bswap32(le);

    printf("Little-endian: 0x%" PRIx32 "\n", le);
    printf("Big-endian:    0x%" PRIx32 "\n", be);

    return 0;
}

Here is the output it produces:

Little-endian: 0x12345678
Big-endian:    0x78563412

And here is the disassembly (without optimization, i.e. -O0):

        uint32_t be = __builtin_bswap32(le);
   0x0000000000400535 <+15>:    mov    -0x8(%rbp),%eax
   0x0000000000400538 <+18>:    bswap  %eax
   0x000000000040053a <+20>:    mov    %eax,-0x4(%rbp)

There is just one BSWAP instruction indeed.

So, if we do care about the performance, we should use those built-in functions instead of any other method of byte reversing. Just my 2 cents.

answered Feb 14, 2018 at 18:10

Andriy Berestovskyy's user avatar

1

I think you can use function htonl(). Network byte order is big endian.

answered Oct 9, 2013 at 15:24

aoak's user avatar

aoakaoak

9831 gold badge11 silver badges20 bronze badges

3

«I swap each bytes right?» -> yes, to convert between little and big endian, you just give the bytes the opposite order.
But at first realize few things:

  • size of uint32_t is 32bits, which is 4 bytes, which is 8 HEX digits
  • mask 0xf retrieves the 4 least significant bits, to retrieve 8 bits, you need 0xff

so in case you want to swap the order of 4 bytes with that kind of masks, you could:

uint32_t res = 0;
b0 = (num & 0xff) << 24;        ; least significant to most significant
b1 = (num & 0xff00) << 8;       ; 2nd least sig. to 2nd most sig.
b2 = (num & 0xff0000) >> 8;     ; 2nd most sig. to 2nd least sig.
b3 = (num & 0xff000000) >> 24;  ; most sig. to least sig.
res = b0 | b1 | b2 | b3 ;

answered Oct 9, 2013 at 15:28

LihO's user avatar

LihOLihO

41.3k11 gold badges99 silver badges167 bronze badges

You could do this:

int x = 0x12345678;

x = ( x >> 24 ) | (( x << 8) & 0x00ff0000 )| ((x >> 8) & 0x0000ff00) | ( x << 24)  ; 

printf("value = %x", x);  // x will be printed as 0x78563412

Spotlight's user avatar

Spotlight

4721 gold badge11 silver badges22 bronze badges

answered Oct 17, 2014 at 3:18

ayyappa ch's user avatar

ayyappa chayyappa ch

952 silver badges9 bronze badges

1

One slightly different way of tackling this that can sometimes be useful is to have a union of the sixteen or thirty-two bit value and an array of chars. I’ve just been doing this when getting serial messages that come in with big endian order, yet am working on a little endian micro.

union MessageLengthUnion
{

    uint16_t asInt;
    uint8_t asChars[2];

};

Then when I get the messages in I put the first received uint8 in .asChars[1], the second in .asChars[0] then I access it as the .asInt part of the union in the rest of my program.

If you have a thirty-two bit value to store you can have the array four long.

chux - Reinstate Monica's user avatar

answered Oct 9, 2013 at 15:37

DiBosco's user avatar

DiBoscoDiBosco

8388 silver badges21 bronze badges

one more suggestion :

unsigned int a = 0xABCDEF23;
a = ((a&(0x0000FFFF)) << 16) | ((a&(0xFFFF0000)) >> 16);
a = ((a&(0x00FF00FF)) << 8) | ((a&(0xFF00FF00)) >>8);
printf("%0x\n",a);

answered Dec 30, 2015 at 14:56

Saurabh Sengar's user avatar

Saurabh SengarSaurabh Sengar

9082 gold badges12 silver badges20 bronze badges

2

I am assuming you are on linux

Include "byteswap.h" & Use int32_t bswap_32(int32_t argument);

It is logical view, In actual see, /usr/include/byteswap.h

ketan's user avatar

ketan

19.2k42 gold badges60 silver badges99 bronze badges

answered Jun 17, 2016 at 3:57

0x47-sci-tech's user avatar

A Simple C program to convert from little to big

#include <stdio.h>

int main() {
unsigned int little=0x1234ABCD,big=0;
unsigned char tmp=0,l;

printf(" Little endian little=%x\n",little);

for(l=0;l < 4;l++) 
{
    tmp=0;
    tmp = little | tmp;
    big = tmp | (big << 8);
    little = little >> 8;
}
printf(" Big endian big=%x\n",big);

return 0;
}

answered Nov 6, 2017 at 17:35

Naresh pothula's user avatar

OP’s code is incorrect for the following reasons:

  • The swaps are being performed on a nibble (4-bit) boundary, instead of a byte (8-bit) boundary.
  • The shift-left << operations of the final four swaps are incorrect, they should be shift-right >> operations and their shift values would also need to be corrected.
  • The use of intermediary storage is unnecessary, and the code can therefore be rewritten to be more concise/recognizable. In doing so, some compilers will be able to better-optimize the code by recognizing the oft-used pattern.

Consider the following code, which efficiently converts an unsigned value:

// Swap endian (big to little) or (little to big)
uint32_t num = 0x12345678;
uint32_t res =
    ((num & 0x000000FF) << 24) |
    ((num & 0x0000FF00) << 8) |
    ((num & 0x00FF0000) >> 8) |
    ((num & 0xFF000000) >> 24);

printf("%0x\n", res);

The result is represented here in both binary and hex, notice how the bytes have swapped:

‭0111 1000 0101 0110 0011 0100 0001 0010‬

78563412

Optimizing

In terms of performance, leave it to the compiler to optimize your code when possible. You should avoid unnecessary data structures like arrays for simple algorithms like this, doing so will usually cause different instruction behavior such as accessing RAM instead of using CPU registers.

Dutchmanjonny's user avatar

answered Jul 29, 2017 at 7:57

Shaun Wilson's user avatar

Shaun WilsonShaun Wilson

8,7273 gold badges50 silver badges48 bronze badges

#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;
}

answered Sep 28, 2022 at 17:31

Moorthy B S's user avatar

1

You can use the lib functions. They boil down to assembly, but if you are open to alternate implementations in C, here they are (assuming int is 32-bits) :

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
}

And the usage is performed like so:

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

answered Aug 10, 2017 at 13:19

netskink's user avatar

netskinknetskink

4,0792 gold badges34 silver badges46 bronze badges

Below is an other approach that was useful for me

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) ;
    }
}

answered Nov 13, 2019 at 17:20

user2552729's user avatar

Below program produce the result as needed:

#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));
}

And also below function can be used:

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

answered Sep 10, 2020 at 16:28

Naren's user avatar

NarenNaren

1591 silver badge7 bronze badges

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

}

answered Mar 24, 2021 at 19:36

naumaan's user avatar

Here is a little function I wrote that works pretty good, its probably not portable to every single machine or as fast a single cpu instruction, but should work for most. It can handle numbers up to 32 byte (256 bit) and works for both big and little endian swaps. The nicest part about this function is you can point it into a byte array coming off or going on the wire and swap the bytes inline before converting.

#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);
}

output:

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

 BigEndian = 0x12345678

 LittleEndian = 0x78563412

 BigEndian = 0x1234567891234567

 LittleEndian = 0x6745239178563412

 BigEndian = 0x1234567891234567

answered Sep 18, 2021 at 12:36

Lewis Miller's user avatar

Endian Converter

Binary Little
Endian:

Binary Big
Endian:

Explanation

Big-endian is an order in which the «big end» (most significant value in the sequence) is
stored
first (at the lowest storage address). Little-endian is an order in which the «little end»
(least significant value in the sequence) is stored first. For example, in a big-endian
computer, the two bytes required for the hexadecimal number 4F52 would be stored as 4F52 in
storage (if 4F is stored at storage address 1000, for example, 52 will be at address 1001).
In a
little-endian system, it would be stored as 524F (52 at address 1000, 4F at 1001).

Hexal
Little Endian:

Hexal
Big Endian:

Explanation

Big-endian is an order in which the «big end» (most significant value in the sequence) is
stored
first (at the lowest storage address). Little-endian is an order in which the «little end»
(least significant value in the sequence) is stored first. For example, in a big-endian
computer, the two bytes required for the hexadecimal number 4F52 would be stored as 4F52 in
storage (if 4F is stored at storage address 1000, for example, 52 will be at address 1001).
In a
little-endian system, it would be stored as 524F (52 at address 1000, 4F at 1001).

This tool shows the conversion from Little Endian Format to Big Endian Format and vice versa. You can choose between the binary and the hexal number format.
When entering a character that does not belong to the corresponding number format, you will be informed about it.
A conversion takes place directly with the input. With the help of the Clear button, all fields are blanked.

Как преобразовать значения big-endian и little-endian в С++?

EDIT: для ясности я должен перевести двоичные данные (значения с плавающей запятой с двойной точностью и 32-разрядные и 64-разрядные целые числа) из одной архитектуры процессора в другую. Это не связано с сетью, поэтому ntoh() и подобные функции здесь не работают.

EDIT # 2: Ответ, который я принял, относится непосредственно к компиляторам, на которых я нацелен (именно поэтому я его выбрал). Однако здесь есть и другие очень хорошие, более портативные ответы.

4b9b3361

Ответ 1

Если вы используете Visual С++, выполните следующие действия: включите intrin.h и вызовите следующие функции:

Для 16-разрядных номеров:

unsigned short _byteswap_ushort(unsigned short value);

Для 32-разрядных номеров:

unsigned long _byteswap_ulong(unsigned long value);

Для 64-разрядных номеров:

unsigned __int64 _byteswap_uint64(unsigned __int64 value);

8-битные номера (символы) не нужно преобразовывать.

Также они определены только для неподписанных значений, которые они также используют для целых чисел со знаком.

Для поплавков и удваивает его сложнее, чем для простых целых чисел, поскольку они могут или не могут быть в байтовом порядке хост-машин. Вы можете получить малоподобные поплавки на машинах большого конца и наоборот.

Другие компиляторы также имеют схожие функции.

В GCC, например, вы можете напрямую позвонить:

int32_t __builtin_bswap32 (int32_t x)
int64_t __builtin_bswap64 (int64_t x)

(нет необходимости включать что-либо). Afaik bits.h объявляет ту же функцию не с gcc-ориентированным способом.

16-битная сводка просто немного повернуть.

Вызов встроенных функций вместо того, чтобы сворачивать ваши собственные, дает вам наилучшую производительность и плотность кодов btw..

Ответ 2

Проще говоря:

#include <climits>

template <typename T>
T swap_endian(T u)
{
    static_assert (CHAR_BIT == 8, "CHAR_BIT != 8");

    union
    {
        T u;
        unsigned char u8[sizeof(T)];
    } source, dest;

    source.u = u;

    for (size_t k = 0; k < sizeof(T); k++)
        dest.u8[k] = source.u8[sizeof(T) - k - 1];

    return dest.u;
}

: swap_endian<uint32_t>(42).

Ответ 3

От Ошибка байтового порядка: Rob Pyke:

Предположим, что ваш поток данных имеет 32-разрядное целое число с кодировкой с маленьким энтиансом. Здесь, как извлечь его (предполагая неподписанные байты):

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

Если это big-endian, вот как его извлечь:

i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);

TL; DR: не беспокойтесь о собственном заказе вашей платформы, все, что считается, — это порядок байтов потока, из которого вы читаете, и вам лучше надеяться, что он будет хорошо определен.

Примечание: в комментарии было отмечено, что при отсутствии явного преобразования типов важно, чтобы data был массивом unsigned char или uint8_t. Использование signed char или char (если подписано) приведет к продвижению data[x] к целому числу и data[x] << 24, потенциально меняющему 1 на знаковый бит, который является UB.

Ответ 4

Если вы делаете это для обеспечения совместимости с сетью/хостом, вы должны использовать:

ntohl() //Network to Host byte order (Long)
htonl() //Host to Network byte order (Long)

ntohs() //Network to Host byte order (Short)
htons() //Host to Network byte order (Short)

Если вы делаете это по какой-то другой причине, один из представленных здесь решений byte_swap будет работать нормально.

Ответ 5

Я сделал несколько предложений из этого сообщения и собрал их вместе, чтобы сформировать это:

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/endian.hpp>
#include <stdexcept>

enum endianness
{
    little_endian,
    big_endian,
    network_endian = big_endian,

    #if defined(BOOST_LITTLE_ENDIAN)
        host_endian = little_endian
    #elif defined(BOOST_BIG_ENDIAN)
        host_endian = big_endian
    #else
        #error "unable to determine system endianness"
    #endif
};

namespace detail {

template<typename T, size_t sz>
struct swap_bytes
{
    inline T operator()(T val)
    {
        throw std::out_of_range("data size");
    }
};

template<typename T>
struct swap_bytes<T, 1>
{
    inline T operator()(T val)
    {
        return val;
    }
};

template<typename T>
struct swap_bytes<T, 2>
{
    inline T operator()(T val)
    {
        return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
    }
};

template<typename T>
struct swap_bytes<T, 4>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff000000) >> 24) |
                (((val) & 0x00ff0000) >>  8) |
                (((val) & 0x0000ff00) <<  8) |
                (((val) & 0x000000ff) << 24));
    }
};

template<>
struct swap_bytes<float, 4>
{
    inline float operator()(float val)
    {
        uint32_t mem =swap_bytes<uint32_t, sizeof(uint32_t)>()(*(uint32_t*)&val);
        return *(float*)&mem;
    }
};

template<typename T>
struct swap_bytes<T, 8>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff00000000000000ull) >> 56) |
                (((val) & 0x00ff000000000000ull) >> 40) |
                (((val) & 0x0000ff0000000000ull) >> 24) |
                (((val) & 0x000000ff00000000ull) >> 8 ) |
                (((val) & 0x00000000ff000000ull) << 8 ) |
                (((val) & 0x0000000000ff0000ull) << 24) |
                (((val) & 0x000000000000ff00ull) << 40) |
                (((val) & 0x00000000000000ffull) << 56));
    }
};

template<>
struct swap_bytes<double, 8>
{
    inline double operator()(double val)
    {
        uint64_t mem =swap_bytes<uint64_t, sizeof(uint64_t)>()(*(uint64_t*)&val);
        return *(double*)&mem;
    }
};

template<endianness from, endianness to, class T>
struct do_byte_swap
{
    inline T operator()(T value)
    {
        return swap_bytes<T, sizeof(T)>()(value);
    }
};
// specialisations when attempting to swap to the same endianess
template<class T> struct do_byte_swap<little_endian, little_endian, T> { inline T operator()(T value) { return value; } };
template<class T> struct do_byte_swap<big_endian,    big_endian,    T> { inline T operator()(T value) { return value; } };

} // namespace detail

template<endianness from, endianness to, class T>
inline T byte_swap(T value)
{
    // ensure the data is only 1, 2, 4 or 8 bytes
    BOOST_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
    // ensure we're only swapping arithmetic types
    BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

    return detail::do_byte_swap<from, to, T>()(value);
}

Ответ 6

Процедура перехода от широкоформатного к малодунному — это то же самое, что и переход от мало-северного к великому.

Вот пример кода:

void swapByteOrder(unsigned short& us)
{
    us = (us >> 8) |
         (us << 8);
}

void swapByteOrder(unsigned int& ui)
{
    ui = (ui >> 24) |
         ((ui<<8) & 0x00FF0000) |
         ((ui>>8) & 0x0000FF00) |
         (ui << 24);
}

void swapByteOrder(unsigned long long& ull)
{
    ull = (ull >> 56) |
          ((ull<<40) & 0x00FF000000000000) |
          ((ull<<24) & 0x0000FF0000000000) |
          ((ull<<8) & 0x000000FF00000000) |
          ((ull>>8) & 0x00000000FF000000) |
          ((ull>>24) & 0x0000000000FF0000) |
          ((ull>>40) & 0x000000000000FF00) |
          (ull << 56);
}

Ответ 7

Существует инструкция по сборке под названием BSWAP, которая будет выполнять своп для вас, очень быстро.
Вы можете прочитать об этом здесь.

Visual Studio, или, точнее, библиотека времени исполнения Visual С++, имеет встроенные функции платформы, называемые _byteswap_ushort(), _byteswap_ulong(), and _byteswap_int64(). Подобное должно существовать для других платформ, но я не знаю, как они будут называться.

Ответ 8

Мы сделали это с помощью шаблонов. Вы можете сделать что-то вроде этого:

// Specialization for 2-byte types.
template<>
inline void endian_byte_swapper< 2 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    ushort* p_dest = reinterpret_cast< ushort* >(dest);
    ushort const* const p_src = reinterpret_cast< ushort const* >(src);
    *p_dest = (*p_src >> 8) | (*p_src << 8);
}

// Specialization for 4-byte types.
template<>
inline void endian_byte_swapper< 4 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    uint* p_dest = reinterpret_cast< uint* >(dest);
    uint const* const p_src = reinterpret_cast< uint const* >(src);
    *p_dest = (*p_src >> 24) | ((*p_src & 0x00ff0000) >> 8) | ((*p_src & 0x0000ff00) << 8) | (*p_src << 24);
}

Ответ 9

Если вы делаете это для передачи данных между различными платформами, смотрите функции ntoh и hton.

Ответ 10

Точно так же вы делаете в C:

short big = 0xdead;
short little = (((big & 0xff)<<8) | ((big & 0xff00)>>8));

Вы также можете объявить вектор unsigned chars, memcpy входного значения в него, перевернуть байты в другой вектор и memcpy байты, но это займет порядка больше, чем бит-twiddling, особенно с 64- бит.

Ответ 11

В большинстве систем POSIX (через него нет в стандарте POSIX) существует файл endian.h, который можно использовать для определения того, какую кодировку использует ваша система. Оттуда это примерно так:

unsigned int change_endian(unsigned int x)
{
    unsigned char *ptr = (unsigned char *)&x;
    return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
}

Это меняет порядок (с обратного порядка байтов на обратный):

Если у вас есть число 0xDEADBEEF (в системе с прямым порядком байтов, сохраненной как 0xEFBEADDE), ptr [0] будет 0xEF, ptr [1] будет 0xBE и т.д.

Но если вы хотите использовать его для работы в сети, то htons, htonl и htonll (и их обратные ntohs, ntohl и ntohll) будут полезны для преобразования порядка хостов в порядок сетей.

Ответ 12

Обратите внимание, что, по крайней мере, для Windows, htonl() намного медленнее, чем их собственный экземпляр _byteswap_ulong(). Первый — это вызов библиотеки DLL в файл ws2_32.dll, последний — одна инструкция сборки BSWAP. Поэтому, если вы пишете какой-то платформозависимый код, предпочитайте использовать встроенные функции для скорости:

#define htonl(x) _byteswap_ulong(x)

Это может быть особенно важно для обработки изображений .PNG, где все целые числа сохраняются в Big Endian с объяснением «Можно использовать htonl()…» {для замедления типичных программ Windows, если вы не подготовлены}.

Ответ 13

На большинстве платформ есть системный заголовочный файл, который обеспечивает эффективные функции byteswap. В Linux он находится в <endian.h>. Вы можете легко его обернуть в С++:

#include <iostream>

#include <endian.h>

template<size_t N> struct SizeT {};

#define BYTESWAPS(bits) \
template<class T> inline T htobe(T t, SizeT<bits / 8>) { return htobe ## bits(t); } \
template<class T> inline T htole(T t, SizeT<bits / 8>) { return htole ## bits(t); } \
template<class T> inline T betoh(T t, SizeT<bits / 8>) { return be ## bits ## toh(t); } \
template<class T> inline T letoh(T t, SizeT<bits / 8>) { return le ## bits ## toh(t); }

BYTESWAPS(16)
BYTESWAPS(32)
BYTESWAPS(64)

#undef BYTESWAPS

template<class T> inline T htobe(T t) { return htobe(t, SizeT<sizeof t>()); }
template<class T> inline T htole(T t) { return htole(t, SizeT<sizeof t>()); }
template<class T> inline T betoh(T t) { return betoh(t, SizeT<sizeof t>()); }
template<class T> inline T letoh(T t) { return letoh(t, SizeT<sizeof t>()); }

int main()
{
    std::cout << std::hex;
    std::cout << htobe(static_cast<unsigned short>(0xfeca)) << '\n';
    std::cout << htobe(0xafbeadde) << '\n';

    // Use ULL suffix to specify integer constant as unsigned long long 
    std::cout << htobe(0xfecaefbeafdeedfeULL) << '\n';
}

Вывод:

cafe
deadbeaf
feeddeafbeefcafe

Ответ 14

Мне нравится этот, только для стиля: -)

long swap(long i) {
    char *c = (char *) &i;
    return * (long *) (char[]) {c[3], c[2], c[1], c[0] };
}

Ответ 15

Серьезно… Я не понимаю, почему все решения являются сложными! Как насчет простейшей, самой общей функции шаблона, которая меняет любой тип любого размера при любых обстоятельствах в любой операционной системе?

template <typename T>
void SwapEnd(T& var)
{
    char* varArray = reinterpret_cast<char*>(&var);
    for(long i = 0; i < static_cast<long>(sizeof(var)/2); i++)
        std::swap(varArray[sizeof(var) - 1 - i],varArray[i]);
}

Это волшебная сила C и С++ вместе! Просто замените исходный символ переменной символом.

Помните, что я не использовал простой оператор присваивания «=», потому что некоторые объекты будут перепутаны, когда энтитантность будет перевернута, а конструктор копирования (или оператор присваивания) не будет работать. Поэтому более надежно копировать их char на char.

Чтобы вызвать его, просто используйте

double x = 5;
SwapEnd(x);

а теперь x различается по контенту.

Ответ 16

У меня есть этот код, который позволяет мне преобразовать из HOST_ENDIAN_ORDER (что бы это ни было) в LITTLE_ENDIAN_ORDER или BIG_ENDIAN_ORDER. Я использую шаблон, поэтому, если я попытаюсь преобразовать из HOST_ENDIAN_ORDER в LITTLE_ENDIAN_ORDER, и они будут одинаковыми для машины, для которой я компилирую, никакой код не будет создан.

Вот код с комментариями:

// We define some constant for little, big and host endianess. Here I use 
// BOOST_LITTLE_ENDIAN/BOOST_BIG_ENDIAN to check the host indianess. If you
// don't want to use boost you will have to modify this part a bit.
enum EEndian
{
  LITTLE_ENDIAN_ORDER,
  BIG_ENDIAN_ORDER,
#if defined(BOOST_LITTLE_ENDIAN)
  HOST_ENDIAN_ORDER = LITTLE_ENDIAN_ORDER
#elif defined(BOOST_BIG_ENDIAN)
  HOST_ENDIAN_ORDER = BIG_ENDIAN_ORDER
#else
#error "Impossible de determiner l'indianness du systeme cible."
#endif
};

// this function swap the bytes of values given it size as a template
// parameter (could sizeof be used?).
template <class T, unsigned int size>
inline T SwapBytes(T value)
{
  union
  {
     T value;
     char bytes[size];
  } in, out;

  in.value = value;

  for (unsigned int i = 0; i < size / 2; ++i)
  {
     out.bytes[i] = in.bytes[size - 1 - i];
     out.bytes[size - 1 - i] = in.bytes[i];
  }

  return out.value;
}

// Here is the function you will use. Again there is two compile-time assertion
// that use the boost librarie. You could probably comment them out, but if you
// do be cautious not to use this function for anything else than integers
// types. This function need to be calles like this :
//
//     int x = someValue;
//     int i = EndianSwapBytes<HOST_ENDIAN_ORDER, BIG_ENDIAN_ORDER>(x);
//
template<EEndian from, EEndian to, class T>
inline T EndianSwapBytes(T value)
{
  // A : La donnée à swapper à une taille de 2, 4 ou 8 octets
  BOOST_STATIC_ASSERT(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);

  // A : La donnée à swapper est d'un type arithmetic
  BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

  // Si from et to sont du même type on ne swap pas.
  if (from == to)
     return value;

  return SwapBytes<T, sizeof(T)>(value);
}

Ответ 17

Если 32-разрядное целое число без знака выглядит как 0xAABBCCDD, равное 2864434397, то такое же 32-разрядное целое число без знака выглядит как 0xDDCCBBAA на процессоре little-endian, который также равен 2864434397.

Если big-endian 16-битный unsigned short выглядит как 0xAABB, который равен 43707, то тот же 16-разрядный беззнаковый короткий выглядит как 0xBBAA на процессоре little-endian, который также равен 43707.

Вот несколько удобных функций #define для обмена байтами от little-endian до big-endian и наоборот →

// can be used for short, unsigned short, word, unsigned word (2-byte types)
#define BYTESWAP16(n) (((n&0xFF00)>>8)|((n&0x00FF)<<8))

// can be used for int or unsigned int or float (4-byte types)
#define BYTESWAP32(n) ((BYTESWAP16((n&0xFFFF0000)>>16))|((BYTESWAP16(n&0x0000FFFF))<<16))

// can be used for unsigned long long or double (8-byte types)
#define BYTESWAP64(n) ((BYTESWAP32((n&0xFFFFFFFF00000000)>>32))|((BYTESWAP32(n&0x00000000FFFFFFFF))<<32))

Ответ 18

Здесь обобщенная версия, которую я придумал с головы, заменил значение на месте. Другие предложения были бы лучше, если производительность была проблемой.

 template<typename T>
    void ByteSwap(T * p)
    {
        for (int i = 0;  i < sizeof(T)/2;  ++i)
            std::swap(((char *)p)[i], ((char *)p)[sizeof(T)-1-i]);
    }

Отказ от ответственности: Я еще не пытался скомпилировать это или протестировать его.

Ответ 19

Если вы берете общий шаблон для реверсирования порядка бит в слове и отбираете часть, которая меняет биты в каждом байте, тогда у вас остается что-то, что только отменяет байты внутри слова. Для 64-бит:

x = ((x & 0x00000000ffffffff) << 32) ^ ((x >> 32) & 0x00000000ffffffff);
x = ((x & 0x0000ffff0000ffff) << 16) ^ ((x >> 16) & 0x0000ffff0000ffff);
x = ((x & 0x00ff00ff00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff00ff00ff);

Компилятор должен очистить лишние операции маскировки (я оставил их, чтобы выделить шаблон), но если это не так, вы можете переписать первую строку следующим образом:

x = ( x                       << 32) ^  (x >> 32);

Это обычно упрощает до одной команды поворота на большинстве архитектур (игнорируя, что вся операция, вероятно, одна инструкция).

В RISC-процессоре большие, сложные константы могут вызвать трудности с компилятором. Однако вы можете тривиально вычислить каждую из констант из предыдущей. Например:

uint64_t k = 0x00000000ffffffff; /* compiler should know a trick for this */
x = ((x & k) << 32) ^ ((x >> 32) & k);
k ^= k << 16;
x = ((x & k) << 16) ^ ((x >> 16) & k);
k ^= k << 8;
x = ((x & k) <<  8) ^ ((x >>  8) & k);

Если вам нравится, вы можете написать это как цикл. Это не будет эффективно, но просто для удовольствия:

int i = sizeof(x) * CHAR_BIT / 2;
uintmax_t k = (1 << i) - 1;
while (i >= 8)
{
    x = ((x & k) << i) ^ ((x >> i) & k);
    i >>= 1;
    k ^= k << i;
}

И для полноты здесь упрощенная 32-битная версия первой формы:

x = ( x               << 16) ^  (x >> 16);
x = ((x & 0x00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff);

Ответ 20

Просто подумал, что я добавил свое собственное решение здесь, так как я его нигде не видел. Это небольшая и портативная С++-шаблонная функция и переносная, которая использует только бит-операции.

template<typename T> inline static T swapByteOrder(const T& val) {
    int totalBytes = sizeof(val);
    T swapped = (T) 0;
    for (int i = 0; i < totalBytes; ++i) {
        swapped |= (val >> (8*(totalBytes-i-1)) & 0xFF) << (8*i);
    }
    return swapped;
}

Ответ 21

Используя приведенные ниже коды, вы можете легко переключаться между BigEndian и LittleEndian

#define uint32_t unsigned 
#define uint16_t unsigned short

#define swap16(x) ((((uint16_t)(x) & 0x00ff)<<8)| \
(((uint16_t)(x) & 0xff00)>>8))

#define swap32(x) ((((uint32_t)(x) & 0x000000ff)<<24)| \
(((uint32_t)(x) & 0x0000ff00)<<8)| \
(((uint32_t)(x) & 0x00ff0000)>>8)| \
(((uint32_t)(x) & 0xff000000)>>24))

Ответ 22

Недавно я написал макрос для этого в C, но он одинаково допустим в С++:

#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)

Он принимает любой тип и меняет байты в переданном аргументе.
Пример использования:

int main(){
    unsigned long long x = 0xABCDEF0123456789;
    printf("Before: %llX\n",x);
    REVERSE_BYTES(x);
    printf("After : %llX\n",x);

    char c[7]="nametag";
    printf("Before: %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
    REVERSE_BYTES(c);
    printf("After : %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
}

Какие принты:

Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman

Вышеописанное прекрасно копируется/вставляется, но здесь многое происходит, поэтому я разбиваю, как он работает по частям:

Первое примечательно, что весь макрос заключен в блок do while(0). Это общая идиома, чтобы разрешить использование обычной точки с запятой после макроса.

Далее следует использование переменной с именем REVERSE_BYTES в качестве счетчика циклов for. Имя самого макроса используется как имя переменной, чтобы гарантировать, что оно не сталкивается с любыми другими символами, которые могут быть в области, где используется макрос. Поскольку имя используется в расширении макроса, оно не будет расширяться снова при использовании в качестве имени переменной здесь.

В цикле for есть два байта, на которые ссылаются, и XOR обменивается (поэтому имя временной переменной не требуется):

((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]

__VA_ARGS__ представляет все, что было передано макросу, и используется для повышения гибкости того, что может быть передано (хотя и не по большому счету). Затем адрес этого аргумента берется и преобразуется в указатель unsigned char, чтобы разрешить свопинг его байтов с помощью подстроки массива [].

Конечным своеобразным моментом является отсутствие брекетов {}. Они не нужны, потому что все шаги в каждом свопе объединены с оператором запятой , что делает их одним утверждением.

Наконец, стоит отметить, что это не идеальный подход, если скорость является главным приоритетом. Если это важный фактор, некоторые из макросов типа или специфических для платформы директив, упомянутых в других ответах, скорее всего, являются лучшим вариантом. Однако этот подход является переносимым для всех типов, всех основных платформ и языков C и С++.

Ответ 23

Я действительно удивлен, что никто не упоминает функции htobeXX и betohXX. Они определены в endian.h и очень похожи на сетевые функции htonXX.

Ответ 24

Ничего себе, я не мог поверить некоторым из ответов, которые я прочитал здесь. На самом деле есть инструкция в сборке, которая делает это быстрее, чем что-либо еще. BSWAP. Вы могли бы просто написать такую ​​функцию…

__declspec(naked) uint32_t EndianSwap(uint32 value)
{
    __asm
    {
        mov eax, dword ptr[esp + 4]
        bswap eax
        ret
    }
}

Это намного быстрее, чем предположения, которые были предложены. Я разобрал их и посмотрел. Вышеупомянутая функция не имеет пролога/эпилога, так что практически нет никаких накладных расходов.

unsigned long _byteswap_ulong(unsigned long value);

Выполнение 16 бит так же просто, за исключением того, что вы будете использовать xchg al, ah. bswap работает только с 32-разрядными регистрами.

64-бит немного сложнее, но не слишком. Намного лучше, чем все вышеприведенные примеры с циклами и шаблонами и т.д.

Здесь есть некоторые оговорки… Во-первых, bswap доступен только на процессоре 80×486 и выше. Кто-нибудь планирует запустить его на 386?!? Если это так, вы все равно можете заменить bswap на…

mov ebx, eax
shr ebx, 16
xchg bl, bh
xchg al, ah
shl eax, 16
or eax, ebx

Также встроенная сборка доступна только в коде x86 в Visual Studio. Голая функция не может быть выровнена, а также недоступна в сборках x64. В этом случае вам придется использовать встроенные функции компилятора.

Ответ 25

Портативная техника для внедрения оптимизаторов-дружественных нестандартных не-inplace endian-аксессуаров. Они работают на каждом компиляторе, каждом выравнивании границ и порядке каждого байта. Эти невыложенные подпрограммы дополняются или обсуждаются в зависимости от исходного кода и выравнивания. Частичный листинг, но вы получите эту идею. BO * — постоянные значения, основанные на упорядочении нативного байта.

uint32_t sw_get_uint32_1234(pu32)
uint32_1234 *pu32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32_1234[0] = (*pu32)[BO32_0];
  bou32.u32_1234[1] = (*pu32)[BO32_1];
  bou32.u32_1234[2] = (*pu32)[BO32_2];
  bou32.u32_1234[3] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_1234(pu32, u32)
uint32_1234 *pu32;
uint32_t u32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_1234[0];
  (*pu32)[BO32_1] = bou32.u32_1234[1];
  (*pu32)[BO32_2] = bou32.u32_1234[2];
  (*pu32)[BO32_3] = bou32.u32_1234[3];
}

#if HAS_SW_INT64
int64 sw_get_int64_12345678(pi64)
int64_12345678 *pi64;
{
  union {
    int64_12345678 i64_12345678;
    int64 i64;
  } boi64;
  boi64.i64_12345678[0] = (*pi64)[BO64_0];
  boi64.i64_12345678[1] = (*pi64)[BO64_1];
  boi64.i64_12345678[2] = (*pi64)[BO64_2];
  boi64.i64_12345678[3] = (*pi64)[BO64_3];
  boi64.i64_12345678[4] = (*pi64)[BO64_4];
  boi64.i64_12345678[5] = (*pi64)[BO64_5];
  boi64.i64_12345678[6] = (*pi64)[BO64_6];
  boi64.i64_12345678[7] = (*pi64)[BO64_7];
  return(boi64.i64);
}
#endif

int32_t sw_get_int32_3412(pi32)
int32_3412 *pi32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32_3412[2] = (*pi32)[BO32_0];
  boi32.i32_3412[3] = (*pi32)[BO32_1];
  boi32.i32_3412[0] = (*pi32)[BO32_2];
  boi32.i32_3412[1] = (*pi32)[BO32_3];
  return(boi32.i32);
}

void sw_set_int32_3412(pi32, i32)
int32_3412 *pi32;
int32_t i32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32 = i32;
  (*pi32)[BO32_0] = boi32.i32_3412[2];
  (*pi32)[BO32_1] = boi32.i32_3412[3];
  (*pi32)[BO32_2] = boi32.i32_3412[0];
  (*pi32)[BO32_3] = boi32.i32_3412[1];
}

uint32_t sw_get_uint32_3412(pu32)
uint32_3412 *pu32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32_3412[2] = (*pu32)[BO32_0];
  bou32.u32_3412[3] = (*pu32)[BO32_1];
  bou32.u32_3412[0] = (*pu32)[BO32_2];
  bou32.u32_3412[1] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_3412(pu32, u32)
uint32_3412 *pu32;
uint32_t u32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_3412[2];
  (*pu32)[BO32_1] = bou32.u32_3412[3];
  (*pu32)[BO32_2] = bou32.u32_3412[0];
  (*pu32)[BO32_3] = bou32.u32_3412[1];
}

float sw_get_float_1234(pf)
float_1234 *pf;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f_1234[0] = (*pf)[BO32_0];
  bof.f_1234[1] = (*pf)[BO32_1];
  bof.f_1234[2] = (*pf)[BO32_2];
  bof.f_1234[3] = (*pf)[BO32_3];
  return(bof.f);
}

void sw_set_float_1234(pf, f)
float_1234 *pf;
float f;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f = (float)f;
  (*pf)[BO32_0] = bof.f_1234[0];
  (*pf)[BO32_1] = bof.f_1234[1];
  (*pf)[BO32_2] = bof.f_1234[2];
  (*pf)[BO32_3] = bof.f_1234[3];
}

double sw_get_double_12345678(pd)
double_12345678 *pd;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d_12345678[0] = (*pd)[BO64_0];
  bod.d_12345678[1] = (*pd)[BO64_1];
  bod.d_12345678[2] = (*pd)[BO64_2];
  bod.d_12345678[3] = (*pd)[BO64_3];
  bod.d_12345678[4] = (*pd)[BO64_4];
  bod.d_12345678[5] = (*pd)[BO64_5];
  bod.d_12345678[6] = (*pd)[BO64_6];
  bod.d_12345678[7] = (*pd)[BO64_7];
  return(bod.d);
}

void sw_set_double_12345678(pd, d)
double_12345678 *pd;
double d;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d = d;
  (*pd)[BO64_0] = bod.d_12345678[0];
  (*pd)[BO64_1] = bod.d_12345678[1];
  (*pd)[BO64_2] = bod.d_12345678[2];
  (*pd)[BO64_3] = bod.d_12345678[3];
  (*pd)[BO64_4] = bod.d_12345678[4];
  (*pd)[BO64_5] = bod.d_12345678[5];
  (*pd)[BO64_6] = bod.d_12345678[6];
  (*pd)[BO64_7] = bod.d_12345678[7];
}

Эти typedefs имеют преимущество в повышении ошибок компилятора, если они не используются с аксессуарами, что уменьшает ошибки забытых аксессуаров.

typedef char int8_1[1], uint8_1[1];

typedef char int16_12[2], uint16_12[2]; /* little endian */
typedef char int16_21[2], uint16_21[2]; /* big endian */

typedef char int24_321[3], uint24_321[3]; /* Alpha Micro, PDP-11 */

typedef char int32_1234[4], uint32_1234[4]; /* little endian */
typedef char int32_3412[4], uint32_3412[4]; /* Alpha Micro, PDP-11 */
typedef char int32_4321[4], uint32_4321[4]; /* big endian */

typedef char int64_12345678[8], uint64_12345678[8]; /* little endian */
typedef char int64_34128756[8], uint64_34128756[8]; /* Alpha Micro, PDP-11 */
typedef char int64_87654321[8], uint64_87654321[8]; /* big endian */

typedef char float_1234[4]; /* little endian */
typedef char float_3412[4]; /* Alpha Micro, PDP-11 */
typedef char float_4321[4]; /* big endian */

typedef char double_12345678[8]; /* little endian */
typedef char double_78563412[8]; /* Alpha Micro? */
typedef char double_87654321[8]; /* big endian */

Ответ 26

Попробуйте Boost::endian и НЕ ВЫПОЛНЯЙТЕ ЭТО СЕБЯ!

Здесь ссылка

Ответ 27

Здесь, как читать двойной, сохраненный в 64-битном формате IEEE 754, даже если ваш хост-компьютер использует другую систему.

/*
* read a double from a stream in ieee754 format regardless of host
*  encoding.
*  fp - the stream
*  bigendian - set to if big bytes first, clear for little bytes
*              first
*
*/
double freadieee754(FILE *fp, int bigendian)
{
    unsigned char buff[8];
    int i;
    double fnorm = 0.0;
    unsigned char temp;
    int sign;
    int exponent;
    double bitval;
    int maski, mask;
    int expbits = 11;
    int significandbits = 52;
    int shift;
    double answer;

    /* read the data */
    for (i = 0; i < 8; i++)
        buff[i] = fgetc(fp);
    /* just reverse if not big-endian*/
    if (!bigendian)
    {
        for (i = 0; i < 4; i++)
        {
            temp = buff[i];
            buff[i] = buff[8 - i - 1];
            buff[8 - i - 1] = temp;
        }
    }
    sign = buff[0] & 0x80 ? -1 : 1;
    /* exponet in raw format*/
    exponent = ((buff[0] & 0x7F) << 4) | ((buff[1] & 0xF0) >> 4);

    /* read inthe mantissa. Top bit is 0.5, the successive bits half*/
    bitval = 0.5;
    maski = 1;
    mask = 0x08;
    for (i = 0; i < significandbits; i++)
    {
        if (buff[maski] & mask)
            fnorm += bitval;

        bitval /= 2.0;
        mask >>= 1;
        if (mask == 0)
        {
            mask = 0x80;
            maski++;
        }
    }
    /* handle zero specially */
    if (exponent == 0 && fnorm == 0)
        return 0.0;

    shift = exponent - ((1 << (expbits - 1)) - 1); /* exponent = shift + bias */
    /* nans have exp 1024 and non-zero mantissa */
    if (shift == 1024 && fnorm != 0)
        return sqrt(-1.0);
    /*infinity*/
    if (shift == 1024 && fnorm == 0)
    {

#ifdef INFINITY
        return sign == 1 ? INFINITY : -INFINITY;
#endif
        return  (sign * 1.0) / 0.0;
    }
    if (shift > -1023)
    {
        answer = ldexp(fnorm + 1.0, shift);
        return answer * sign;
    }
    else
    {
        /* denormalised numbers */
        if (fnorm == 0.0)
            return 0.0;
        shift = -1022;
        while (fnorm < 1.0)
        {
            fnorm *= 2;
            shift--;
        }
        answer = ldexp(fnorm, shift);
        return answer * sign;
    }
}

Для остальной части набора функций, включая записи и целые подпрограммы, см. мой проект github

https://github.com/MalcolmMcLean/ieee754

Ответ 28

Замена байтов трюком ye olde 3-step-xor вокруг центра в функции шаблона дает гибкое, быстрое решение O (ln2), которое не требует библиотеки, стиль здесь также отклоняет типы 1 байта:

template<typename T>void swap(T &t){
    for(uint8_t pivot = 0; pivot < sizeof(t)/2; pivot ++){
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
        *((uint8_t *)&t+sizeof(t)-1- pivot) ^= *((uint8_t *)&t + pivot);
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
    }
}

Ответ 29

Похоже, безопасным способом было бы использовать htons для каждого слова. Итак, если у вас есть…

std::vector<uint16_t> storage(n);  // where n is the number to be converted

// the following would do the trick
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });

Выше было бы не работать, если бы вы работали в системе с прямым порядком байтов, поэтому я бы искал то, что ваша платформа использует в качестве условия времени компиляции, чтобы решить, является ли htons запретом. В конце концов, это O (n). На Mac это было бы что-то вроде…

#if (__DARWIN_BYTE_ORDER != __DARWIN_BIG_ENDIAN)
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });
#endif

Ответ 30

Посмотрите на бит-сдвиг, так как это в основном все, что вам нужно сделать, чтобы поменять местами немного → большой endian. Затем, в зависимости от размера бита, вы изменяете способ смещения бит.

  • Home
  • VBForums
  • Visual Basic
  • Visual Basic 6 and Earlier
  • [RESOLVED] Convert String from Little Endian to BIG Endian

  1. Apr 9th, 2014, 03:52 PM


    #1

    some1uk03 is offline

    Thread Starter


    Frenzied Member

    some1uk03's Avatar


    Resolved [RESOLVED] Convert String from Little Endian to BIG Endian

    From my previous thread: http://www.vbforums.com/showthread.php?760441

    I need a way to reverse the byte order from Little Endian to BIG Endian.

    All my research leads to converting Longs but I need to convert a STRING from Little Endian to BIG Endian.

    Any ideas?

    _____________________________________________________________________

    —-If this post has helped you. Please take time to Rate it.
    —-If you’ve solved your problem, then please mark it as RESOLVED from Thread Tools.


  2. Apr 9th, 2014, 04:37 PM


    #2

    cobraide is offline


    Hyperactive Member


    Re: Convert String from Little Endian to BIG Endian


  3. Apr 9th, 2014, 05:23 PM


    #3

    Re: Convert String from Little Endian to BIG Endian

    Not 100% sure but I think you reverse every two-byte pair and if it’s four-bytes you do same and then reverse the two-byte pairs

    Example:

    2-Byte:

    Code:

    Little      Big
    ob 0a ----> 0a 0b

    4-Byte:

    Code:

    Little            Big
    0d 0c 0b 0a ----> 0a 0b 0c 0d

    Kind of looks like you just reverse the string

    Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.


  4. Apr 9th, 2014, 05:42 PM


    #4

    Re: Convert String from Little Endian to BIG Endian

    I can think of two possible approaches.

    One is to use an ADO Stream object, which in text mode can translate between character encodings using MIME values assigned to its CharSet property. As the documentation states:

    For a list of the character set strings that is known by a system, see the subkeys of HKEY_CLASSES_ROOT\MIME\Database\Charset in the Windows Registry.

    Most systems ought to have «unicodeFFFE» there and that’s the one you’d want.

    Of course you’ll need to deal with the BOM that the Stream will probably insert upon conversion.

    The other is to loop over the String character by character calling the htons function for each character. This would be more reasonable than treating binary data as text, always a sucker’s game and it can lead to data corruption.

    But big-endian data is rare in Windows or any x86/x64 system. If you are getting something like raw PCM data from a foreign platform then you are thinking the wrong way around, and what you start with is big-endian and you want to convert it to little-endian. To be «correct» you’d use ntohs instead of htons.

    If this works out for you it can be sped up a little by using a typelib instead of incurring the overhead of Declare-based calls.


  5. Apr 9th, 2014, 06:17 PM


    #5

    Re: Convert String from Little Endian to BIG Endian

    Normally strings are a sequence of characters, and often that sequence is ASCII, which is one byte per character.
    So, if you’re dealing with ASCII, there is no such thing as BigEndian or LittleEndian, because the characters are in order byte by byte. Since you’re reading some sort of binary file with Wav data in it, and converting it to «true» wav file format, I don’t see that unicode comes into play with the way you read and write the data and manipulate with string functions.

    Ok, I looked back at your other thread.
    So you’re suspecting the data being read in is BigEndian, and you want to convert it to LittleEndian (since .wav files as defined my Microsoft had the wave data in LittleEndian format).
    I can’t see that being the case since you say there is just a little hiss, which you need a good ear to detect.
    If the Endian of the data was reversed, you would hear nothing but bleating distorted garbage coming from the speakers.
    But, if you want to continue, since you’ve already specified the data as being 16-bit and VB6 will be expecting ASCII to and from a file, you should just swap the characters in pairs, as jmsrickland said, to swap the endianess of the data, but have the volume turned down when you play it.

    I’m not sure why your read and write the data into and out of a string anyway. It is extremely inefficient and you have to use the Asc function all over the place to convert the characters into numbers, which would be unnecessary if you just read the types as needed.
    Plus you’re using twice the memory needed since VB6 will be reading «ASCII» converting it to unicode for internal use, and then reversing the process converting unicode back into ASCII when producing the file.

    I think I would do as you mentioned at one point, just declare an array of Integer (16 bit values).
    In fact, I wouldn’t have made RAMBuffer a string.
    If you made it a byte array, it would be easier for a lot of the parsing and you could use CopyMemory to copy from the byte array into the Integer array for the wavedata portion.
    Or, you could just read the individual pieces of data straight from the binary file into your variables, along the lines of the following (I could be off by 1, as I can’t test the code and am making some assumptions)

    Code:

    Open PPath For Binary Access Read As #fFile
             
            Dim lPtr as Long
            lPtr = xPos 
            xPos = xPos + RAMChunkSize + 8
    
            mHeader.wFileLen = RAMChunkSize + 8
           
            get #fFile, lPtr + 17, mHeader.wNumChannels
            get #fFile, , mHeader.wBitsPerSample
            get #fFile, , mHeader.wSamplingFreq
            get #fFile, , gmHeader.wNumSamples
            redim mHeader.WavData(mHeader.wFileLen \ 2)   'assumes WavData is integer array. You could use byte array and not \ 2
            get #fFile, ,mHeader.WavData  'also assumes WavData immediately follows NumSamples field.
    Close #fFile

    Last edited by passel; Apr 9th, 2014 at 06:24 PM.


  6. Apr 9th, 2014, 06:28 PM


    #6

    Re: Convert String from Little Endian to BIG Endian

    The Winsock function works ok. Though I won’t claim this process is a speed demon it doesn’t seem to be terrible.

    Name:  sshot.jpg
Views: 8781
Size:  83.4 KB

    Bizarrely enough the site converted my compact and legible PNG to a bulky and ugly JPG. Go figure!


  7. Apr 9th, 2014, 06:30 PM


    #7

    some1uk03 is offline

    Thread Starter


    Frenzied Member

    some1uk03's Avatar


    Re: Convert String from Little Endian to BIG Endian

    Ill.. give these a try…

    Last edited by some1uk03; Apr 9th, 2014 at 06:39 PM.

    _____________________________________________________________________

    —-If this post has helped you. Please take time to Rate it.
    —-If you’ve solved your problem, then please mark it as RESOLVED from Thread Tools.


  8. Apr 9th, 2014, 06:36 PM


    #8

    Re: Convert String from Little Endian to BIG Endian

    Well…

    PCM

    When more than one byte is used to represent a PCM sample, the byte order (big endian vs. little endian) must be known. Due to the widespread use of little-endian Intel CPUs, little-endian PCM tends to be the most common byte orientation.


  9. Apr 10th, 2014, 05:21 AM


    #9

    some1uk03 is offline

    Thread Starter


    Frenzied Member

    some1uk03's Avatar


    Re: Convert String from Little Endian to BIG Endian

    dilettante:

    The other is to loop over the String character by character calling the htons function for each character. This would be more reasonable than treating binary data as text, always a sucker’s game and it can lead to data corruption.

    But big-endian data is rare in Windows or any x86/x64 system. If you are getting something like raw PCM data from a foreign platform then you are thinking the wrong way around, and what you start with is big-endian and you want to convert it to little-endian. To be «correct» you’d use ntohs instead of htons.

    I came accross hTons & Ntons when researching. Something to try but I think there are otherways without using these:
    Yes its a RAW PCM that I’m getting & yes it is a foreign platform [not windows] but I seem to be sure that I’m reading small endian and data needs to be read as Big Endian.
    More like i need to do a BYTE REVERSE.

    NICE TOOL By the way… it will come in handy for my projects…

    passel:

    Ok, I looked back at your other thread.
    So you’re suspecting the data being read in is BigEndian, and you want to convert it to LittleEndian (since .wav files as defined my Microsoft had the wave data in LittleEndian format).
    I can’t see that being the case since you say there is just a little hiss, which you need a good ear to detect.

    If the Endian of the data was reversed, you would hear nothing but bleating distorted garbage coming from the speakers.
    But, if you want to continue, since you’ve already specified the data as being 16-bit and VB6 will be expecting ASCII to and from a file, you should just swap the characters in pairs, as jmsrickland said, to swap the endianess of the data, but have the volume turned down when you play it.

    You’re right I’ve been working testing & comparing. Now I get proper garbage and NOISE not just a slight hmm….

    I’ve tried swapping every 2 characters in pairs but that doesn’t hepl :/

    I even tried reDimming appropriately & loading the data as a () BYTE but same thing.

    I’ve got this piece of code where you can SwapEndians but it is only viable for LONGS [4bytes]

    Code:

    Public Function SwapEndian01(ByVal dw As Long) As Long
    ' by Anonymous, not dated
      CopyMemory ByVal VarPtr(SwapEndian01) + 3, dw, 1
      CopyMemory ByVal VarPtr(SwapEndian01) + 2, ByVal VarPtr(dw) + 1, 1
      CopyMemory ByVal VarPtr(SwapEndian01) + 1, ByVal VarPtr(dw) + 2, 1
      CopyMemory SwapEndian01, ByVal VarPtr(dw) + 3, 1
    End Function

    How do i get this to work on a per Byte bases ?

    Interesting Thread: http://www.xtremevbtalk.com/showthread.php?t=182207

    Last edited by some1uk03; Apr 10th, 2014 at 05:37 AM.

    _____________________________________________________________________

    —-If this post has helped you. Please take time to Rate it.
    —-If you’ve solved your problem, then please mark it as RESOLVED from Thread Tools.


  10. Apr 10th, 2014, 09:11 AM


    #10

    Re: Convert String from Little Endian to BIG Endian

    To convert numbers from LittleEndian to BigEndian (and vice-versa) you just swap the order of the bytes.
    If you litterally wanted to use that same code, then you would just act on two bytes rather than four.
    I don’t have VB6 on this computer so will have to wing it

    Code:

    Public Function SwapEndian02(ByVal dw As Integer) as Integer
    ' by Anonymous, not dated
      CopyMemory ByVal VarPtr(SwapEndian01) + 1, dw, 1  'copy byte 0 to 1
      CopyMemory SwapEndian01, ByVal VarPtr(dw) + 1, 1  'copy byte 1 to 0
    End Function

    You said you already swapped bytes, and you got the expected resulting noise.
    My point in my previous post was because you said the resulting wave file you created works, but has a slight, hard to hear hiss to it, that you didn’t have an Endian problem.
    But, if you wanted to convince yourself that you didn’t have an Endian problem, having you swap the bytes you then created an endian problem, and heard the resulting garbage.
    Now you know what an Endian problem sounds like. It would be nothing like the original sound.

    A slight hiss in the playback is not an endian problem.
    Are you sure the oriiginal file doesn’t have that same hiss.
    I don’t know what kind of artifacts in the data might or the mechanics of reproduction would result in the hiss, but you might want to research that and quit playing around with non-existent endian issue.
    Perhaps the «volume» is too low, so if you mutiply all the 16bit values by 2, you can increase the «recorded» volume, so you would then turn down the amplification and the resultiing hiss would be lessened, sort of a Dolby type process.
    Or perhaps there is a setting in the header that isn’t quite right, so caused the decoding to be weak in volume, so you have to over amplify and thus magnify the hiss.
    I don’t know, but bottom line is this thread never had to be created because the endianess of the data had to be already correct. Hiss is not an endian problem.


  11. Apr 10th, 2014, 09:21 AM


    #11

    some1uk03 is offline

    Thread Starter


    Frenzied Member

    some1uk03's Avatar


    Re: Convert String from Little Endian to BIG Endian

    This is so confusing now:

    I uploaded a sample of the RAW PCM data on my other thread: http://www.vbforums.com/showthread.php?760441

    If I read the Data +1 Byte from Original, then the sound plays with with SLIGHT HISS
    If I read the Data from 0 [Which is where I should] then I get the BIG BZZZZ noise [which leads me to a ByteOrder issue]

    The original File doesn’t have the HISS because I’ve checked with other programs and they PlayBack without the HISS…

    Funny thing is: I have a software called WAVELab if you know. If i load theData [littleEndian] then I hear the same thing.. I hear a BIG bzzz NOISE….
    But if I reload theData and select the Byte Order as BIG Endian it sounds PERFECT….

    So I can only assume the problem definitely is with ByteOrdering & Encoding ?

    _____________________________________________________________________

    —-If this post has helped you. Please take time to Rate it.
    —-If you’ve solved your problem, then please mark it as RESOLVED from Thread Tools.


  12. Apr 10th, 2014, 10:11 AM


    #12

    Re: Convert String from Little Endian to BIG Endian

    Brief comment:

    Since you can read the data into a Byte array a simple swap loop is preferable to my

    ntohs loop code in post #6 above. I see that this is done in the recent code snippet posted in the other thread (post #13 there). Good move.


  13. Apr 10th, 2014, 12:36 PM


    #13

    Re: Convert String from Little Endian to BIG Endian

    Quote Originally Posted by some1uk03
    View Post


    The original File doesn’t have the HISS because I’ve checked with other programs and they PlayBack without the HISS…

    Funny thing is: I have a software called WAVELab if you know. If i load theData [littleEndian] then I hear the same thing.. I hear a BIG bzzz NOISE….
    But if I reload theData and select the Byte Order as BIG Endian it sounds PERFECT….
    So I can only assume the problem definitely is with ByteOrdering & Encoding ?

    Is WAVELab just playing the data, or does it create (or have the option to create) a .wav file.
    If it could create a wav file then you could examine what it created against what you’re creating to see where the difference is.
    I didn’t realize you posted an example in the other thread, so perhaps once I get home from work later, I can possibly take a look at the conversion code in actual use, rather than just «on paper».


  14. Apr 10th, 2014, 12:51 PM


    #14

    Re: Convert String from Little Endian to BIG Endian

    Are you sure you are not a byte off? That happened to me once and the sound had a low tone hiss like sound.

    Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.


  15. Apr 10th, 2014, 12:53 PM


    #15

    some1uk03 is offline

    Thread Starter


    Frenzied Member

    some1uk03's Avatar


    Re: Convert String from Little Endian to BIG Endian

    Problem now resolved. It’s on my other thread. It was a byte order issue afterall…

    Thanks to everyone for their help..

    _____________________________________________________________________

    —-If this post has helped you. Please take time to Rate it.
    —-If you’ve solved your problem, then please mark it as RESOLVED from Thread Tools.


  • Home
  • VBForums
  • Visual Basic
  • Visual Basic 6 and Earlier
  • [RESOLVED] Convert String from Little Endian to BIG Endian

Tags for this Thread


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
  • BB code is On
  • Smilies are On
  • [IMG] code is On
  • [VIDEO] code is On
  • HTML code is Off

Forum Rules


Click Here to Expand Forum to Full Width

  • Windows list all used ports
  • Windows linux что это такое
  • Windows key iso windows 7
  • Windows l2tp маршрут по умолчанию
  • Windows linux скачать с официального сайта