I want to know how to convert big-endian numbers to native numbers in Delphi. I am porting some C++ code in that I came across:
unsigned long blockLength = *blockLengthPtr++ << 24;
blockLength |= *blockLengthPtr++ << 16;
blockLength |= *blockLengthPtr++ << 8;
blockLength |= *blockLengthPtr;
unsigned long dataLength = *dataLengthPtr++ << 24;
dataLength |= *dataLengthPtr++ << 16;
dataLength |= *dataLengthPtr++ << 8;
dataLength |= *dataLengthPtr;
I am not familiar with C++, so I don't understand what those operators do.
To do this, we shift the rightmost 8 bits by 24 to the left so that it becomes the leftmost 8 bits. We left shift the right middle byte by 16 (to store it as the left middle byte) We left shift the left middle byte by 8 (to store it as the right muddle byte) We finally left shift the leftmost byte by 24 to the left.
The x86 processors use little-endian byte ordering. The least significant byte (LSB) of an integer is stored at the lowest address of the integer. The most significant byte is stored at the highest address for data items in this processor. For example, byte 7 is the most significant byte for 64-bit processors.
Big endian is the default byte ordering for all TCP/IP network protocols and it is not rare at all. TypedArrays are not little endian by default. They actually use the endianness of the underlying operating system.
If it is little-endian, it would be stored as “01 00 00 00”. The program checks the first byte by dereferencing the cptr pointer. If it equals to 0, it means the processor is big-endian(“00 00 00 01”), If it equals to 1, it means the processor is little-endian (“01 00 00 00”).
Andreas's answer is a pretty good example of how to do it in pure pascal, but it still looks kinda awkward, just like the C++ code. This can actually be done in a single assembly instruction, though which one depends on whether you're using 32-bit or 16-bit integers:
function SwapEndian32(Value: integer): integer; register;
asm
bswap eax
end;
function SwapEndian16(Value: smallint): smallint; register;
asm
rol ax, 8
end;
To reverse the order of the bits:
procedure SwapEndiannessOfBits(var Value: cardinal);
var
tmp: cardinal;
i: Integer;
begin
tmp := 0;
for i := 0 to 8*sizeof(Value) - 1 do
inc(tmp, ((Value shr i) and $1) shl (8*sizeof(Value) - i - 1));
Value := tmp;
end;
To reverse the order of the bytes:
procedure SwapEndiannessOfBytes(var Value: cardinal);
var
tmp: cardinal;
i: Integer;
begin
tmp := 0;
for i := 0 to sizeof(Value) - 1 do
inc(tmp, ((Value shr (8*i)) and $FF) shl (8*(sizeof(Value) - i - 1)));
Value := tmp;
end;
I think the last one is what you are looking for. Most likely there are faster and more elegant solutions, though.
Disclaimer: I might be totally wrong. I feel a bit confused at the moment. Hopefully someone else will see this question and provide a more definite answer!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With