You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* two abi-equivalent, but nominatively distinct structs */
struct A {
int a;
int b;
};
struct B {
int a;
int b;
};
/* what if you want the following macro to fail with an error message about "incompatible types" if you pass in a B instead of an A upon expansion? */
#define SOME_MACRO(SOME_STRUCT) do {\
(SOME_STRUCT)->a = 100;\
(SOME_STRUCT)->b = 200;\
} while (0)
/* ...you do this */
extern int _ensure_is_struct_A(struct A _);
#define SOME_MACRO_TYPE_SAFE(SOME_STRUCT) do {\
/* how to write an empty statement in C89 that doesn't emit warnings: (void) <some expression>; */
/* also, did you know? the operand of sizeof is not evaluated unless it's a VLA (a C99-onwards feature), and because it's not evaluated, the linker doesn't trip up looking for the implementation of _ensure_is_struct_A(). */
/* and voila, some level of type safety in macros without blowing up your linter, pragma-free! */
/* when this macro expands, you will get an error like "cannot pass value of type struct B to struct A" instead of it either succeeding or giving you some other, unhelpful error. */
SOME_MACRO_TYPE_SAFE(&i_am_a_b_struct);
/*
TODO: explain why (including and beyond the obvious) this may be useful
*/
/* i'm sure this is probably already a very well-known trick among erudites, but i figured i'd put this somewhere for my own reference. if any viewers have comments or notice an oversight, let me know! */