Convert some ints into a byte array without allocations?

Johannes Pfau via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Jan 16 11:32:08 PST 2016


Am Sat, 16 Jan 2016 18:05:46 +0000
schrieb Samson Smith <fsdf at dsfd.com>:

> On Saturday, 16 January 2016 at 16:28:21 UTC, Jonathan M Davis 
> wrote:
> >
> > But it will be less error-prone to use those functions, and if 
> > you _do_ actually need to swap endianness, then they're exactly 
> > what you should be using. We've had cases that have come up 
> > where using those functions prevented bugs precisely because 
> > the person writing the code got the sizes wrong (and the 
> > compiler complained, since nativeToBigEndian and friends deal 
> > with the sizes in a typesafe manner).
> >
> > - Jonathan M Davis  
> 
> If I'm hoping to have my hash come out the same on both bigendian 
> and littleendian machines but not send the results between 
> machines, should I take these precautions? I want one machine to 
> send the other a seed (in an endian safe way) and have both 
> machines generate the same hashes.
> 
> Here's the relevant code:
> 
> uint coordHash(int x, int y, uint seed){
> 	seed = FNV1a((cast(ubyte*) &x)[0 .. x.sizeof], seed);
> 	return FNV1a((cast(ubyte*) &y)[0 .. y.sizeof], seed);
> }
> // Byte order matters for the below function
> uint FNV1a(ubyte[] bytes, uint code){
> 	for(int iii = 0; iii < bytes.length; ++iii){
>          	code ^= bytes[iii];
>          	code *= FNV_PRIME_32;
> 	}
> 	return code;
> }
> 
> Am I going to get the same outcome on all machines or would a 
> byte array be divided up in reverse order to what I'd expect on 
> some machines? If it is... I don't mind writing separate versions 
> depending on endianness with 
> version(BigEndian)/version(LittleEndian) to get around a runtime 
> check... I'm just unsure of how endianness factors into the order 
> of an array...

If you use the simple pointer cast you will end up with different byte
orders on little vs big endian machines. Endianness does not affect
array order in general:

ubyte[] myArray = [1, 2, 3, 4];
myArray[0] == 1, myArray[1] == 2, ...


This is the same on big vs little endian machines. Endianness does
affect the representation of (multi-byte)numbers:

int a = 42;
ubyte[4] b = *cast(ubyte[4])&a;

This will generate [42, 0, 0, 0] on little endian, [0, 0, 0, 42] on big
endian.


So if you want the same byte output for all architectures, just choose
either big or little endian (which one doesn't matter). Then convert
the values on the other architecture (e.g. if you choose little endian,
do nothing on little endian, swap bytes on big endian).


TLDR; Just use nativeToBigEndian or nativeToLittleEndian from
std.bitmanip, these functions do the right thing. These functions do not
use runtime checks, they use version(Big/LittleEndian)
internally. nativeToBigEndian does not do anything on big endian
machines, nativeToLittleEndian doesn't do anything on little endian
machines.


More information about the Digitalmars-d-learn mailing list