zephyr/include/toolchain/zephyr_stdint.h

49 lines
1.4 KiB
C
Raw Normal View History

stdint.h: streamline type definitions Compilers (at least gcc and clang) already provide definitions to create standard types and their range. For example, __INT16_TYPE__ is normally defined as a short to be used with the int16_t typedef, and __INT16_MAX__ is defined as 32767. So it makes sense to rely on them rather than hardcoding our own, especially for the fast types where the compiler itself knows what basic type is best. Using compiler provided definitions makes even more sense when dealing with 64-bit targets where some types such as intptr_t and size_t must have a different size and range. Those definitions are then adjusted by the compiler directly. However there are two cases for which we should override those definitions: * The __INT32_TYPE__ definition on 32-bit targets vary between an int and a long int depending on the architecture and configuration. Notably, all compilers shipped with the Zephyr SDK, except for the i586-zephyr-elfiamcu variant, define __INT32_TYPE__ to a long int. Whereas, all Linux configurations for gcc, both 32-bit and 64-bit, always define __INT32_TYPE__ as an int. Having variability here is not welcome as pointers to a long int and to an int are not deemed compatible by the compiler, and printing an int32_t defined with a long using %d makes the compiler to complain, even if they're the same size on 32-bit targets. Given that an int is always 32 bits on all targets we might care about, and given that Zephyr hardcoded int32_t to an int before, then we just redefine __INT32_TYPE__ and derrivatives to an int to keep the peace in the code. * The confusion also exists with __INTPTR_TYPE__. Looking again at the Zephyr SDK, it is defined as an int, even even when __INT32_TYPE__ is initially a long int. One notable exception is i586-zephyr-elf where __INTPTR_TYPE__ is a long int even when using -m32. On 64-bit targets this is always a long int. So let's redefine __INTPTR_TYPE__ to always be a long int on Zephyr which simplifies the code, works for both 32-bit and 64-bit targets, and mimics what the Linux kernel does. Only a few print format strings needed adjustment. In those two cases, there is a safeguard to ensure the type we're enforcing has the right size and fail the build otherwise. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2019-06-06 00:19:37 +08:00
/*
* Copyright (c) 2019 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_STDINT_H_
#define ZEPHYR_INCLUDE_TOOLCHAIN_STDINT_H_
/*
* Some gcc versions and/or configurations as found in the Zephyr SDK
* (questionably) define __INT32_TYPE__ and derrivatives as a long int
* which makes the printf format checker to complain about long vs int
* mismatch when %u is given a u32_t argument, and u32_t pointers not
* being compatible with int pointers. Let's redefine them to follow
* common expectations and usage.
*/
#if __SIZEOF_INT__ != 4
#error "unexpected int width"
#endif
#undef __INT32_TYPE__
#undef __UINT32_TYPE__
#undef __INT_LEAST32_TYPE__
#undef __UINT_LEAST32_TYPE__
#define __INT32_TYPE__ int
#define __UINT32_TYPE__ unsigned int
#define __INT_LEAST32_TYPE__ __INT32_TYPE__
#define __UINT_LEAST32_TYPE__ __UINT32_TYPE__
/*
* The confusion also exists with __INTPTR_TYPE__ which is either an int
* (even when __INT32_TYPE__ is a long int) or a long int. Let's redefine
* it to a long int to get some uniformity. Doing so also makes it compatible
* with LP64 (64-bit) targets where a long is always 64-bit wide.
*/
#if __SIZEOF_POINTER__ != __SIZEOF_LONG__
#error "unexpected size difference between pointers and long ints"
#endif
#undef __INTPTR_TYPE__
#undef __UINTPTR_TYPE__
#define __INTPTR_TYPE__ long int
#define __UINTPTR_TYPE__ long unsigned int
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_STDINT_H_ */