0

I need a C++ function that returns the value of four consecutive bytes interpreted as a bigendian long. A pointer to the first byte should be updated to point after the last. I have tried the following code:

inline int32_t bigendianlong(unsigned char * &p)  
{  
  return (((int32_t)*p++ << 8 | *p++) << 8 | *p++) << 8 | *p++;  
}  

For instance, if p points to 00 00 00 A0 I would expect the result to be 160, but it is 0. How come?

PAF
  • 23
  • 4

2 Answers2

3

The issue is explained clearly by this warning (emitted by the compiler):

./endian.cpp:23:25: warning: multiple unsequenced modifications to 'p' [-Wunsequenced]
    return (((int32_t)*p++ << 8 | *p++) << 8 | *p++) << 8 | *p++;

Breaking down the logic in the function in order to explicitly specify sequence points...

inline int32_t bigendianlong(unsigned char * &p)
{
    int32_t result = *p++;
    result = (result << 8) + *p++;
    result = (result << 8) + *p++;
    result = (result << 8) + *p++;
    return result;
}

... will solve it

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Thank you. I thought the parentheses would account for unambiguous sequencing. My compiler gives no warning. – PAF Oct 06 '15 at 11:53
  • The parentheses ensure he order of arithmetic, not the side-effects of ++. The standard's wording explicitly allows the implementation to apply the post-increment at any time after the use of p and before the next sequence point (comma or semicolon). Shame you got no warning. Perhaps turn up your warning levels? – Richard Hodges Oct 06 '15 at 14:06
0

This function is named ntohl() (convert Network TO Host byte order Long) on both Unix and Windows, or g_ntohl() in glib. Add 4 to your pointer afterward. If you want to roll your own, a union type whose members are a uint32_t and a uint8_t[4] will be useful.

Davislor
  • 14,674
  • 2
  • 34
  • 49