3.5 Data Conversion for Interoperability

3.5.1 Low-Level Code, Bit-Level Operations

The logic for converting between the big-endian and little-endian formats is actually quite straight forward. 3.4 and 3.5 show that you can convert one format to the other by swapping the appropriate bytes.

To account for communication over a network that has machines with diverse architectures, the data is usually converted in network-byte order at the transmitting end before being sent to the network, and the received data is converted back to host-byte order after the receipt of the packet at the destination host. You can use conversion routines such as ntohl() and htonl() convert from network to host-byte order and from host to network-byte order respectively.

For member data in structure, union, or class objects, the structure members are aligned to the highest bytes of the size of any member to prevent performance penalties. In the following example, the size of mystruct is 8 bytes.

// 4-byte alignment
struct mystruct {
    char a;   // size = 1 byte
              // 3 bytes padding
    int i;    // size = 4 bytes

However, in the next example, the size of mystruct is 16 bytes as the i member is 8 bytes in size.

// 8-byte alignment
struct mystruct {
    char a;   // size = 1 byte
              // 7 bytes padding
    double i; // size = 8 bytes

3.5.1 Low-Level Code, Bit-Level Operations

When migrating from a 32-bit application to a 64-bit application, bit-shifting operations can lead to errors. Untyped integral constants are assumed to be of type unsigned int. During shifting, this assumption can lead to unexpected truncation. For example, the maximum possible value of i in the following code sample is 31 because the implicit type of 1 is unsigned int.

long j = 1 << i;

To allow the shift to work correctly on a 64-bit system, use 1L instead of 1:

long j = 1L << i;