problem source: "wchar_t is unsigned or signed" https://stackoverflow.com/a/11953419 "The signedness of wchar_t is unspecified. The standard only says (3.9.1/5):" C standard further does not guarantee sizes, which you typedef. So they should be checked with macros/compiler.
From playing with the idea to write a test framework, I got the following macros to check sizes and signedness. Unfortunately you do not write compatibility of the C standard (C11 mandates _Static_assert), so you might need to adapt them further.
For example, typedef unsigned short wchar16_t; is wrong and the user must specify it, if is necessary and for portability must _Static_assert it. The best you can do is to provide example files, so from my point of view this should also be BSD0 licensed to make clear that stuff must be potentially modified etc. If you have a complete list of architectures or would accept all possible architectures, that would look different. ;)
typedef unsigned short wchar16_t;
One solution to this is:
// user.h // necessary for testing #include <stdint.h> // abi: (u)int8_t .. (u)int64_t // optional (see below for usage) #include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE // necessary for testing #define assert(a) if( !( a ) ) \ { \ fprintf( stderr, "%s:%d assertion failure of (%s)\n", \ __FILE__, __LINE__, #a ); \ exit(EXIT_FAILURE); \ } \ _Static_assert(1, "") // assume: true == 1 // necessary for testing #ifdef IS_SIGNED #error "IS_SIGNED already defined" #else #define IS_SIGNED(Type) (((Type)-1) < 0) #endif // IS_SIGNED // optional, but recommended #ifndef EXIT_SUCCESS #error "EXIT_SUCCESS undefined, usually 0" #endif #ifndef EXIT_FAILURE #error "EXIT_FAILURE undefined, usually 1" #endif static_assert(EXIT_SUCCESS == 0, "err: exit not 0"); static_assert(EXIT_FAILURE == 1, "err: exit not 1"); //#define EXIT_SUCCESS 0 //#define EXIT_FAILURE 1 // optional, but recommended (to adjust) static_assert(IS_SIGNED(char), "err: char is unsigned");
// ntalltypes.h # include "user.h" // all of the typedefs ... #if defined(__NEED_wchar16_t) && !defined(__DEFINED_wchar16_t) typedef unsigned short wchar16_t; #define __DEFINED_wchar16_t #endif typedef unsigned short wchar16_t; // all of them static_assert(sizeof(char) == 1, "err: char not 1 byte"); static_assert(IS_SIGNED(signed char), "err: IS_SIGNED signed char"); static_assert(sizeof(signed char) == 1, "err: char not 1 byte"); static_assert(sizeof(int8_t) == 1, "err: int8_t not 1 byte"); static_assert(sizeof(int16_t) == 2, "err: int16_t not 2 byte"); static_assert(sizeof(int32_t) == 4, "err: int32_t not 4 byte"); static_assert(sizeof(int64_t) == 8, "err: int64_t not 8 byte"); static_assert((!IS_SIGNED(unsigned char)), "err: IS_SIGNED unsigned char"); static_assert(sizeof(unsigned char) == 1, "err: char not 1 byte"); static_assert(sizeof(uint8_t) == 1, "err: uint8_t not 1 byte"); static_assert(sizeof(uint16_t) == 2, "err: uint16_t not 2 byte"); static_assert(sizeof(uint32_t) == 4, "err: uint32_t not 4 byte"); static_assert(sizeof(uint64_t) == 8, "err: uint64_t not 8 byte");
If you think otherwise, please add the Assumptions (unchecked things) and Assertions (checked things) to README.md.
Let me know, what you think.
One can autogenerate those definitions with grepping for __SIZEOF_INT__ and co as explained here https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
__SIZEOF_INT__
args = [ "-target", "aarch64-linux-gnu", "-E", // -dM is cleaner, but -dD preserves iteration order. "-dD", // No need for line-markers. "-P", "-nostdinc", "-Iinclude", "-Iinclude/uapi", "arch/arm64/include/uapi/asm/unistd.h", ] ; clang args
__has_include("limits.h") __has_include("stdint.h") + check macro definition existence
to autogenerate the static assertions for checking if code assumptions also hold on the other platforms. Without limits and stdint all bets are off.
This also works for signedness of char, ie with https://exchangetuts.com/what-causes-a-char-to-be-signed-or-unsigned-when-using-gcc-1639592646188352
see also https://github.com/ziglang/zig/pull/11447
Login to comment on this ticket.