Skip to content
C Basics: Encode a 32-Bit Value with Explicit Byte Order

C Basics: Encode a 32-Bit Value with Explicit Byte Order

November 1, 2026

A binary field should have a documented byte order rather than inherit the host machine’s representation. Encode a 32-bit unsigned value into four octets and reject an incomplete input before decoding.

Prepare a scratch directory

Tested on Linux x86_64 with GCC 14.2.0. Install GCC and the C standard-library development headers, and make gcc available on PATH. You also need Bash, a text editor, and mktemp, rm, and rmdir. No third-party C library is required.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as uint32-byte-order-demo.c:

#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

static void encode_big_endian(uint32_t value, uint8_t output[4])
{
    output[0] = (uint8_t)(value >> 24);
    output[1] = (uint8_t)(value >> 16);
    output[2] = (uint8_t)(value >> 8);
    output[3] = (uint8_t)value;
}

static bool decode_big_endian(const uint8_t *input, size_t length, uint32_t *output)
{
    if (length != 4 || input == NULL || output == NULL) {
        return false;
    }
    *output = ((uint32_t)input[0] << 24) |
              ((uint32_t)input[1] << 16) |
              ((uint32_t)input[2] << 8) |
              (uint32_t)input[3];
    return true;
}

int main(void)
{
    uint8_t bytes[4];
    uint32_t decoded = 0;
    encode_big_endian(UINT32_C(0x89abcdef), bytes);
    printf("Bytes: %02x %02x %02x %02x\n", (unsigned)bytes[0],
           (unsigned)bytes[1], (unsigned)bytes[2], (unsigned)bytes[3]);
    if (!decode_big_endian(bytes, sizeof bytes, &decoded)) {
        return 1;
    }
    printf("Decoded: %08" PRIx32 "\n", decoded);
    printf("Short input rejected: %s\n",
           !decode_big_endian(bytes, 3, &decoded) ? "yes" : "no");
    return 0;
}

Compile and run it. The && prevents execution if compilation fails:

gcc -std=c17 -Wall -Wextra -Werror -pedantic uint32-byte-order-demo.c -o uint32-byte-order-demo &&
./uint32-byte-order-demo

Observed output:

Bytes: 89 ab cd ef
Decoded: 89abcdef
Short input rejected: yes

Read the result

The most significant octet is stored first. Conversion to uint32_t occurs before each left shift, avoiding a signed-int shift of the high octet on this target. The implementation accesses byte elements directly, so it does not require an aligned integer pointer or a packed structure.

Apply it carefully

This example requires the optional exact-width uint8_t and uint32_t types, available on the tested Linux target. The encoder’s caller must supply four writable elements; array notation in its parameter does not enforce that size. The decoder requires exactly four readable octets. Validate decoded lengths and other protocol fields separately before allocating memory.

The GNU reference documents the relevant interface or language rules.

Clean up

Remove only the source and executable created here, then remove the empty practice directory:

rm -- uint32-byte-order-demo.c uint32-byte-order-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect the remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on