C Basics: Encode a 32-Bit Value with Explicit Byte Order
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 1Run 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-demoObserved output:
Bytes: 89 ab cd ef
Decoded: 89abcdef
Short input rejected: yesRead 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_directoryIf the directory is not empty, inspect the remaining contents before removing anything else.
Acknowledgements
This post was created with assistance from AI.