-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test abi sizes #1
Comments
whoa I've never seen static_assert before. I've actually already added a runtime time for This test will currently get run when you run |
Related to this would be breaking abi changes, ie from Microsoft that can be tested with this tool: Related stackoverflow question: https://stackoverflow.com/questions/9233118/library-abi-compatibility-between-versions-of-visual-studio This would go into the direction of automatic generation of macro includes + header to include as checks for the caller site. Ideally, there would be macro aliasing with a reasonable compatibility symbol, but I have no idea how big of a maintenance mess this would be. |
One working version for me without the #include <stdint.h> // uint32_t, uint8_t
#include <stdlib.h> // exit
#include <stdio.h> // fprintf
#ifndef __cplusplus // disable clang complains
#ifdef TRUE
#error "TRUE already defined"
#else
#define TRUE (1==1)
#endif
#ifdef FALSE
#error "False already defined"
#else
#define FALSE (!TRUE)
#endif
// existence of typedefs can not be checked within macros
//#define _TYPEDEF_
typedef enum { false = FALSE, true } bool;
//#endif
// potential necessity: custom printf and exit for the platform
// unfortunately we dont have __COLUMN__ as macro
#define assert(a) if( !( a ) ) \
{ \
fprintf( stderr, "%s:%d assertion failure of (%s)\n", \
__FILE__, __LINE__, #a ); \
exit( 1 ); \
}
#ifdef static_assert
#error "static_assert already defined"
#else
#define static_assert _Static_assert // since C11
#endif
#ifdef IS_SIGNED
#error "IS_SIGNED already defined"
#else
#define IS_SIGNED(Type) (((Type)-1) < 0)
#endif
//static_assert(IS_SIGNED(char) == false, "char is signed"); // ERRORS on x86_64 Linux (glibc/musl)
static_assert(IS_SIGNED(char), "char is unsigned"); // NO ERROR on x86_64 Linux (glibc/musl)
#endif // __cplusplus A rather hacky, but very efficient+compact+lazy, way to generate the headers/write the sizes for src/include/$(package)/uint64.h: $(sysdeps)/sysdeps src/headers/bits-header src/headers/bits-footer src/headers/bits-lendian src/headers/bits-bendian src/headers/bits-template src/headers/uint64-ulong64 src/headers/uint64-noulong64 src/headers/uint64-defs src/headers/uint64-macros
exec tools/gen-bits.sh $(sysdeps)/sysdeps 64 21 25 17 65 > $@ |
update of script, which just works on a toy project https://github.com/matu3ba/pbcd/blob/master/common.h #ifndef __cplusplus // disable clang complains
#include <stdint.h> // abi: uint32_t, uint8_t
#include <stdlib.h> // assert: exit
#include <stdio.h> // assert: fprintf
#ifdef TRUE
#error "TRUE already defined"
#else
#define TRUE (1==1)
#endif
#ifdef FALSE
#error "False already defined"
#else
#define FALSE (!TRUE)
#endif
// existence of typedefs can not be checked within macros
//#define _TYPEDEF_
typedef enum { false = FALSE, true } bool;
//#endif
#ifdef static_assert
#error "static_assert already defined"
#else
#define static_assert _Static_assert // since C11
#endif
// potential necessity: custom printf and exit for the platform
// unfortunately we dont have __COLUMN__ as macro
#define assert(a) if( !( a ) ) \
{ \
fprintf( stderr, "%s:%d assertion failure of (%s)\n", \
__FILE__, __LINE__, #a ); \
exit( 1 ); \
} \
static_assert(true, "")
#ifdef IS_SIGNED
#error "IS_SIGNED already defined"
#else
#define IS_SIGNED(Type) (((Type)-1) < 0)
#endif
static_assert(IS_SIGNED(char), "err: char is unsigned");
static_assert(sizeof(char) == 1, "err: char not 1 byte");
static_assert(sizeof(unsigned char) == 1, "err: char not 1 byte");
static_assert(sizeof(signed 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");
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(sizeof(uint128_t) == 16, "err: uint128_t not 16 byte"); poorly supported
//static_assert(sizeof(int128_t) == 16, "err: int128_t not 16 byte"); poorly supported
#endif // __cplusplus |
Please do not define the reserved Also asserting the sizeof |
Thats true, but the user can override this via external code (from a different compiler/vendor) for size reduction, so it is no hard guarantee (so strictly speaking requires additional checks) https://stackoverflow.com/a/4446591/9306292. Typical examples are DSPs, which tend to be word-addressable via 4 bytes and one can reduce this to 1 byte. There should be an explicit check to make clear, that this is not a supported use case. Other than that #include <stdbool.h>
#include <stddef.h>
#include <stdint.h> can be assumed. for C99. ansi c has no stdint making it wild. see also https://en.cppreference.com/w/c/header.
You are correct, I messed this up with CHAR_BIT context. |
Just to keep in mind, if you every choose to add assertions for typecheck and want to remain c++ compatible: // C11's Generic selection: Return constant 1, if type and 0 otherwise
// Keep things clean via stringification
#define STATIC_ASSERT_H(x) _Static_assert(x, #x)
#define STATIC_ASSERT(x) STATIC_ASSERT_H(x)
#define OBJ_IS_OF_TYPE(Type, Obj) _Generic(Obj, Type: 1, default: 0)
// Note: C++11 has other utilities and is incompatible with _Static_assert
// #include <type_traits>
// #define OBJ_IS_OF_TYPE(Type, Obj) std::is_same<decltype(Obj), Type>::value>
// #define STATIC_ASSERT(Input) static_assert(Input)
// { Usage
// #include <time.h>
// STATIC_ASSERT(OBJ_IS_OF_TYPE(timespecval1.tv_sec, int64_t));
// STATIC_ASSERT(OBJ_IS_OF_TYPE(timespecval1.tv_nsec, int64_t));
// }
// Hygienic macros
#define TEST_FUNC(a,b) \
do { \
STATIC_ASSERT(OBJ_IS_OF_TYPE(a, int64_t)); \
STATIC_ASSERT(OBJ_IS_OF_TYPE(b, int64_t)); \
} while(0) |
Zig ensures types have properly defined sizes. C does not.
For example,
char
is implementation defined and typically signed. However, it also can be unsigned on some targets.Practical example:
Your implementation of of
strlen
usesHowever, you export
size_t strlen(const char *s);
, which does not ensure the behavior.Macros for usage
A generalization can be applied to the other type sizes.
The text was updated successfully, but these errors were encountered: