www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - bit twiddling (endianness)

reply Lutger <lutger.blijdestijn gmail.com> writes:
Hi, I need to convert a uint to 4 ubytes in big endian order for which I 
have written the function below. The thing is, I'm not 100% sure it is 
correct for Big Endian systems, would somebody be so kind as to inform 
me if this will work?

void concatUint(inout ubyte[] bytestream, uint num)
{
     bytestream.length = bytestream.length + 4;
     static if (std.system.endian == Endian.LittleEndian)
     {
         bytestream[$-4] = num >> 24;
         bytestream[$-3] = num >> 16;
         bytestream[$-2] = num >> 8;
         bytestream[$-1] = num;
     }
     else // big endian
     {
         bytestream[$-4] = num;
         bytestream[$-3] = num >> 8;
         bytestream[$-2] = num >> 16;
         bytestream[$-1] = num >> 24;
     }
}
Jan 08 2007
next sibling parent Daniel Keep <daniel.keep+lists gmail.com> writes:
Lutger wrote:
 Hi, I need to convert a uint to 4 ubytes in big endian order for which I 
 have written the function below. The thing is, I'm not 100% sure it is 
 correct for Big Endian systems, would somebody be so kind as to inform 
 me if this will work?
 
 void concatUint(inout ubyte[] bytestream, uint num)
 {
     bytestream.length = bytestream.length + 4;
     static if (std.system.endian == Endian.LittleEndian)
     {
         bytestream[$-4] = num >> 24;
         bytestream[$-3] = num >> 16;
         bytestream[$-2] = num >> 8;
         bytestream[$-1] = num;
     }
     else // big endian
     {
         bytestream[$-4] = num;
         bytestream[$-3] = num >> 8;
         bytestream[$-2] = num >> 16;
         bytestream[$-1] = num >> 24;
     }
 }

Taking, as an example, 0x0A0B0C0D: for little endian it should be stored as 0x0D0C0B0A, and for big endian it should be 0x0A0B0C0D. 0x0A0B0C0D >> 24 == 0x0A, so I *think* you've got them backwards. http://en.wikipedia.org/wiki/Little_Endian#Big-endian -- Daniel
Jan 08 2007
prev sibling next sibling parent reply torhu <fake address.dude> writes:
Lutger wrote:
 Hi, I need to convert a uint to 4 ubytes in big endian order for which I 
 have written the function below. The thing is, I'm not 100% sure it is 
 correct for Big Endian systems, would somebody be so kind as to inform 
 me if this will work?
 
 void concatUint(inout ubyte[] bytestream, uint num)
 {
      bytestream.length = bytestream.length + 4;
      static if (std.system.endian == Endian.LittleEndian)
      {
          bytestream[$-4] = num >> 24;
          bytestream[$-3] = num >> 16;
          bytestream[$-2] = num >> 8;
          bytestream[$-1] = num;
      }
      else // big endian
      {
          bytestream[$-4] = num;
          bytestream[$-3] = num >> 8;
          bytestream[$-2] = num >> 16;
          bytestream[$-1] = num >> 24;
      }
 }

Since you haven't done any weird casting, the compiler (or is it cpu?) knows that num is an uint. So the bit shifting will behave like num is big endian, no matter the endianness of the system. In other words, your code for little endian systems is correct for big endian too. But your big endian code swaps the byte order, resulting in little endian order in bytestream.
Jan 08 2007
next sibling parent Daniel Keep <daniel.keep+lists gmail.com> writes:
torhu wrote:
 Lutger wrote:
 
 Hi, I need to convert a uint to 4 ubytes in big endian order for which 
 I have written the function below. The thing is, I'm not 100% sure it 
 is correct for Big Endian systems, would somebody be so kind as to 
 inform me if this will work?

 void concatUint(inout ubyte[] bytestream, uint num)
 {
      bytestream.length = bytestream.length + 4;
      static if (std.system.endian == Endian.LittleEndian)
      {
          bytestream[$-4] = num >> 24;
          bytestream[$-3] = num >> 16;
          bytestream[$-2] = num >> 8;
          bytestream[$-1] = num;
      }
      else // big endian
      {
          bytestream[$-4] = num;
          bytestream[$-3] = num >> 8;
          bytestream[$-2] = num >> 16;
          bytestream[$-1] = num >> 24;
      }
 }

Since you haven't done any weird casting, the compiler (or is it cpu?) knows that num is an uint. So the bit shifting will behave like num is big endian, no matter the endianness of the system. In other words, your code for little endian systems is correct for big endian too. But your big endian code swaps the byte order, resulting in little endian order in bytestream.

Yup: realised what it was he *actually* wanted about ten seconds ago. Ya beat me to it :P -- Daniel
Jan 08 2007
prev sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
torhu wrote:
 Lutger wrote:
 Hi, I need to convert a uint to 4 ubytes in big endian order for which 
 I have written the function below. The thing is, I'm not 100% sure it 
 is correct for Big Endian systems, would somebody be so kind as to 
 inform me if this will work?

 void concatUint(inout ubyte[] bytestream, uint num)
 {
      bytestream.length = bytestream.length + 4;
      static if (std.system.endian == Endian.LittleEndian)
      {
          bytestream[$-4] = num >> 24;
          bytestream[$-3] = num >> 16;
          bytestream[$-2] = num >> 8;
          bytestream[$-1] = num;
      }
      else // big endian
      {
          bytestream[$-4] = num;
          bytestream[$-3] = num >> 8;
          bytestream[$-2] = num >> 16;
          bytestream[$-1] = num >> 24;
      }
 }

Since you haven't done any weird casting, the compiler (or is it cpu?) knows that num is an uint. So the bit shifting will behave like num is big endian, no matter the endianness of the system. In other words, your code for little endian systems is correct for big endian too. But your big endian code swaps the byte order, resulting in little endian order in bytestream.

That explains a lot, especially why I wasn't able to figure it out! Now I wonder how I have got this weird assumption in my head that it would work different for big / little endian systems. Thank you very much for clearing this up.
Jan 08 2007
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Lutger wrote:
 Hi, I need to convert a uint to 4 ubytes in big endian order for which I 
 have written the function below. The thing is, I'm not 100% sure it is 
 correct for Big Endian systems, would somebody be so kind as to inform 
 me if this will work?
 
 void concatUint(inout ubyte[] bytestream, uint num)
 {
     bytestream.length = bytestream.length + 4;
     static if (std.system.endian == Endian.LittleEndian)

torhu is right - your code doesn't need to interrogate the platform byte order. But for future reference, if you ever do want to write endian-dependent code, you might version (LittleEndian) and version (BigEndian) nicer than examining std.system.endian. Stewart.
Jan 10 2007
parent Lutger <lutger.blijdestijn gmail.com> writes:
Stewart Gordon wrote:
 But for future reference, if you ever do want to write endian-dependent 
 code, you might version (LittleEndian) and version (BigEndian) nicer 
 than examining std.system.endian.
 
 Stewart.

Cool, I've missed those somehow.
Jan 11 2007