mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
Merge pull request #20310 from maribu/libc/endian
sys/libc: add endian.h
This commit is contained in:
commit
e085ad02af
114
sys/libc/include/endian.h
Normal file
114
sys/libc/include/endian.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Otto-von-Guericke-Universität Magdeburg
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup posix
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief libc header for endian conversion
|
||||
*
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@posteo.net>
|
||||
*/
|
||||
|
||||
#ifndef ENDIAN_H
|
||||
#define ENDIAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @brief A numeric constant representing little endian byte order
|
||||
*/
|
||||
#define LITTLE_ENDIAN implementation_defined
|
||||
|
||||
/**
|
||||
* @brief A numeric constant representing big endian byte order
|
||||
*/
|
||||
#define BIG_ENDIAN implementation_defined
|
||||
|
||||
/**
|
||||
* @brief A numeric constant representing PDP endian byte order
|
||||
*/
|
||||
#define PDP_ENDIAN implementation_defined
|
||||
|
||||
/**
|
||||
* @brief The byte order of this machines indicated by the constant
|
||||
* @ref BIG_ENDIAN or @ref LITTLE_ENDIAN
|
||||
*
|
||||
* @note This numeric constant is available at preprocessor time, so you
|
||||
* can compare this to @ref BIG_ENDIAN or @ref LITTLE_ENDIAN in
|
||||
* `#if` directives.
|
||||
*/
|
||||
#define BYTE_ORDER <LITTLE_ENDIAN or BIG_ENDIAN>
|
||||
|
||||
uint16_t htobe16(uint16_t host_16bits); /**< host to big endian, 16 bit */
|
||||
uint16_t htole16(uint16_t host_16bits); /**< host to little endian, 16 bit */
|
||||
uint16_t be16toh(uint16_t big_endian_16bits); /**< big endian to host, 16 bit */
|
||||
uint16_t le16toh(uint16_t little_endian_16bits);/**< little endian to host, 16 bit */
|
||||
|
||||
uint32_t htobe32(uint32_t host_32bits); /**< host to big endian, 32 bit */
|
||||
uint32_t htole32(uint32_t host_32bits); /**< host to little endian, 32 bit */
|
||||
uint32_t be32toh(uint32_t big_endian_32bits); /**< big endian to host, 32 bit */
|
||||
uint32_t le32toh(uint32_t little_endian_32bits);/**< little endian to host, 32 bit */
|
||||
|
||||
uint64_t htobe64(uint64_t host_64bits); /**< host to big endian, 64 bit */
|
||||
uint64_t htole64(uint64_t host_64bits); /**< host to little endian, 64 bit */
|
||||
uint64_t be64toh(uint64_t big_endian_64bits); /**< big endian to host, 64 bit */
|
||||
uint64_t le64toh(uint64_t little_endian_64bits);/**< little endian to host, 64 bit */
|
||||
|
||||
#else /* DOXYGEN */
|
||||
|
||||
#define LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define BIG_ENDIAN _BIG_ENDIAN
|
||||
#define PDP_ENDIAN _PDP_ENDIAN
|
||||
#define BYTE_ORDER _BYTE_ORDER
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define htobe16(_x) __builtin_bswap16(_x)
|
||||
# define htole16(_x) ((__uint16_t)(_x))
|
||||
# define be16toh(_x) __builtin_bswap16(_x)
|
||||
# define le16toh(_x) ((__uint16_t)(_x))
|
||||
# define htobe32(_x) __builtin_bswap32(_x)
|
||||
# define htole32(_x) ((__uint32_t)(_x))
|
||||
# define be32toh(_x) __builtin_bswap32(_x)
|
||||
# define le32toh(_x) ((__uint32_t)(_x))
|
||||
# define htobe64(_x) __builtin_bswap64(_x)
|
||||
# define htole64(_x) ((__uint64_t)(_x))
|
||||
# define be64toh(_x) __builtin_bswap64(_x)
|
||||
# define le64toh(_x) ((__uint64_t)(_x))
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
# define htole16(_x) __builtin_bswap16(_x)
|
||||
# define htobe16(_x) ((__uint16_t)(_x))
|
||||
# define le16toh(_x) __builtin_bswap16(_x)
|
||||
# define be16toh(_x) ((__uint16_t)(_x))
|
||||
# define htole32(_x) __builtin_bswap32(_x)
|
||||
# define htobe32(_x) ((__uint32_t)(_x))
|
||||
# define le32toh(_x) __builtin_bswap32(_x)
|
||||
# define be32toh(_x) ((__uint32_t)(_x))
|
||||
# define htole64(_x) __builtin_bswap64(_x)
|
||||
# define htobe64(_x) ((__uint64_t)(_x))
|
||||
# define le64toh(_x) __builtin_bswap64(_x)
|
||||
# define be64toh(_x) ((__uint64_t)(_x))
|
||||
#else
|
||||
# error "Byte order not supported"
|
||||
#endif
|
||||
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ENDIAN_H */
|
||||
/** @} */
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <endian.h>
|
||||
#include "string_utils.h"
|
||||
|
||||
#include "tests-libc.h"
|
||||
@ -39,11 +40,64 @@ static void test_libc_memchk(void)
|
||||
TEST_ASSERT(memchk(buffer, 0xff, sizeof(buffer)) == &buffer[5]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Unit test ensuring `<endian.h>` is provided and correct across
|
||||
* all platforms
|
||||
* @{
|
||||
*/
|
||||
union u16 {
|
||||
uint8_t as_bytes[2];
|
||||
uint16_t as_number;
|
||||
};
|
||||
|
||||
union u32 {
|
||||
uint8_t as_bytes[4];
|
||||
uint32_t as_number;
|
||||
};
|
||||
|
||||
union u64 {
|
||||
uint8_t as_bytes[8];
|
||||
uint64_t as_number;
|
||||
};
|
||||
|
||||
static void test_libc_endian(void)
|
||||
{
|
||||
/* format the numbers 0x0102, 0x01020304 and 0x0102030405060708
|
||||
* in little/big endian format by hand: */
|
||||
const uint16_t u16_host = 0x0102;
|
||||
const union u16 u16_be = { .as_bytes = { 0x01, 0x02 } };
|
||||
const union u16 u16_le = { .as_bytes = { 0x02, 0x01 } };
|
||||
const uint32_t u32_host = 0x01020304;
|
||||
const union u32 u32_be = { .as_bytes = { 0x01, 0x02, 0x03, 0x04 } };
|
||||
const union u32 u32_le = { .as_bytes = { 0x04, 0x03, 0x02, 0x01 } };
|
||||
const uint64_t u64_host = 0x0102030405060708;
|
||||
const union u64 u64_be = { .as_bytes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 } };
|
||||
const union u64 u64_le = { .as_bytes = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 } };
|
||||
|
||||
/* check from host to big/little endian */
|
||||
TEST_ASSERT_EQUAL_INT(htobe16(u16_host), u16_be.as_number);
|
||||
TEST_ASSERT_EQUAL_INT(htole16(u16_host), u16_le.as_number);
|
||||
TEST_ASSERT_EQUAL_INT(htobe32(u32_host), u32_be.as_number);
|
||||
TEST_ASSERT_EQUAL_INT(htole32(u32_host), u32_le.as_number);
|
||||
TEST_ASSERT_EQUAL_INT(htobe64(u64_host), u64_be.as_number);
|
||||
TEST_ASSERT_EQUAL_INT(htole64(u64_host), u64_le.as_number);
|
||||
|
||||
/* check little/big endian to host */
|
||||
TEST_ASSERT_EQUAL_INT(be16toh(u16_be.as_number), u16_host);
|
||||
TEST_ASSERT_EQUAL_INT(le16toh(u16_le.as_number), u16_host);
|
||||
TEST_ASSERT_EQUAL_INT(be32toh(u32_be.as_number), u32_host);
|
||||
TEST_ASSERT_EQUAL_INT(le32toh(u32_le.as_number), u32_host);
|
||||
TEST_ASSERT_EQUAL_INT(be64toh(u64_be.as_number), u64_host);
|
||||
TEST_ASSERT_EQUAL_INT(le64toh(u64_le.as_number), u64_host);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
Test *tests_libc_tests(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
new_TestFixture(test_libc_strscpy),
|
||||
new_TestFixture(test_libc_memchk),
|
||||
new_TestFixture(test_libc_endian),
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(libc_tests, NULL, NULL, fixtures);
|
||||
|
Loading…
Reference in New Issue
Block a user