How can compile-time static asserts be implemented in C (not C++), with particular emphasis on GCC?
-
For C11 on GCC/Clang for equality check with int32_ts, you can even get the compiler to print the incorrect value if it fails! https://stackoverflow.com/q/53310844/1495449 – Jetski S-type Nov 09 '21 at 00:01
16 Answers
C11 standard adds the _Static_assert
keyword.
This is implemented since gcc-4.6:
_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */
The first slot needs to be an integral constant expression. The second slot is a constant string literal which can be long (_Static_assert(0, L"assertion of doom!")
).
I should note that this is also implemented in recent versions of clang.
-
13*[...seems to be implemented by gcc, by clang...]* You can be more *assertive* that that ;-) `_Static_assert` is part of the C11 standard and any compiler that supports C11, will have it. – P.P Oct 12 '14 at 20:30
-
2Can this be used at file scope (outside any function)? Because I get `error: expected declaration specifiers or '...' before 'sizeof'` for line `static_assert( sizeof(int) == sizeof(long int), "Error!);` (I am using C not C++ by the way) – user10607 Nov 21 '14 at 06:25
-
@user10607 I'm surprised this doesn't work.. Wait, you're missing a quote at the end of your error string. Put that in and get back. This works for me on gcc-4.9: `_Static_assert( sizeof(int) == sizeof(long int), "Error!");` On my macine I get the error. – emsr Nov 21 '14 at 14:04
-
I have gcc 4.8.2 on Ubuntu. The missing quote was a comment typo (I had it in code). This is the first line in a file after a couple of header includes. The compiler gives me two exact same errors: `error: expected declaration specifiers or '...' before 'sizeof'` AND `error: expected declaration specifiers or '...' before string constant` (he is referring to the `"Error!"`string) (also: I am compiling with -std=c11. When putting the declaration inside a function all works well (fails and succeeds as expected)) – user10607 Nov 21 '14 at 14:20
-
2@user10607 I also had to specify -std=gnu11 on the command line. I'm really surprised there'd be a difference between 4.8 and 4.8. I have a source with just the one line. I also used the C standard `_Static_assert` not the C++ish `static_assert`. You need to `#include
to get the static_assert macro. – emsr Nov 21 '14 at 14:43 -
Thanks that's it! I was using a c++ oriented IDE that auto highlighted `static_assert` as valid even though I forgot the
. Noob trap :)) – user10607 Nov 21 '14 at 15:45 -
Here's a simple macro that utilizes gcc's `_Static_assert()` in C and C++11's `static_assert` so that it works with `gcc`, `gcc -std=c90`, `gcc -std=c99`, `gcc -std=c11`, and `g++ -std=c++11`, etc: https://stackoverflow.com/a/54993033/4561887 – Gabriel Staples Mar 04 '19 at 23:25
-
This works in function and non-function scope (but not inside structs,unions).
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
STATIC_ASSERT(1,this_should_be_true);
int main()
{
STATIC_ASSERT(1,this_should_be_true);
}
If the compile time assertion could not be matched, then an almost intelligible message is generated by GCC
sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative
The macro could or should be changed to generate a unique name for the typedef (i.e. concatenate
__LINE__
at the end of thestatic_assert_...
name)Instead of a ternary, this could be used as well
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1]
which happens to work even on the rusty olde cc65 (for the 6502 cpu) compiler.
UPDATE:
For completeness sake, here's the version with __LINE__
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X) COMPILE_TIME_ASSERT2(X,__LINE__)
COMPILE_TIME_ASSERT(sizeof(long)==8);
int main()
{
COMPILE_TIME_ASSERT(sizeof(int)==4);
}
UPDATE2: GCC specific code
GCC 4.3 (I guess) introduced the "error" and "warning" function attributes. If a call to a function with that attribute could not be eliminated through dead code elimination (or other measures) then an error or warning is generated. This can be used to make compile time asserts with user defined failure descriptions. It remains to determine how they can be used in namespace scope without resorting to a dummy function:
#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })
// never to be called.
static void my_constraints()
{
CTC(sizeof(long)==8);
CTC(sizeof(int)==4);
}
int main()
{
}
And this is how it looks like:
$ gcc-mp-4.5 -m32 sas.c
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true

- 14,740
- 10
- 56
- 88

- 28,058
- 10
- 66
- 83
-
2In Visual Studio it just says "Negative subscript", not mentioning the variable name... – szx Apr 25 '12 at 15:20
-
-
1Regarding the last (GCC 4.3+-specific) solution: This is very powerful, as it can check anything the optimizer can figure out, but it fails if optimization is not enabled. The bare minimum optimization level (`-Og`) may often be enough for this to work, however, and should not interfere with debugging. One may consider making the static assert a no-op or runtime assert if `__OPTIMIZE__` (and `__GNUC__`) is not defined. – Søren Løvborg Sep 17 '14 at 16:39
-
In the Code snippet with LINE version (UPDATE: For completeness sake, here's the version with `LINE) , when compiling, it errors at the line (STATIC_ASSERT(X,static_assertion_at_line_##L)), which can be corrected by adding one more level like below: #define COMPILE_TIME_ASSERT4(X,L) static_assert(X,#L); #define COMPILE_TIME_ASSERT3(X,L) COMPILE_TIME_ASSERT3(X,""Assertion at:##L""); – sundar May 27 '16 at 11:51
-
I use something similar to the `__LINE__` version in gcc 4.1.1 ... with occasional annoyance when two different headers happen to have one on the same numbered line! – M.M Apr 11 '17 at 13:36
-
The `typedef` version works with all compilers. However, if the compiler supports `__attribute__((unused))`, it is convenient to append it, lest being fussed by [`-Wunused-local-typedef`](https://stackoverflow.com/questions/9587509/gnu-gcc-how-to-suppress-warning-typedef-was-ignored-in-this-declaration-enab). – Ale Dec 14 '17 at 15:41
-
This can silently succeeds if the argument is not a constant. For instance this does NOT complain if `n` is variable: `STATIC_ASSERT(n == 42, always_succeeds)`. Inside a function this typedefs a variable array which is fine. It does fail if n is a compile-time constant different from 42. Very confusing. – MarcH Jun 28 '21 at 04:53
-
-
You said, "This works in function and non-function scope **(but not inside structs,unions)**." This is true in C, but in C++, where I am using this for pre-C++11, it works perfectly, **including in both structs and unions!** Please update your answer to state that, as that's very important info. for anyone looking for a pre-C++11 static assert solution. – Gabriel Staples Apr 17 '22 at 03:18
-
I massively just [rewrote my answer and presented all of my new findings, including what I said in my previous comment, here.](https://stackoverflow.com/a/54993033/4561887) – Gabriel Staples Apr 17 '22 at 21:17
-
@GabrielStaples But why `ar[1]` in the successful case? `ar[0]` is also permitted and produces [leaner code](https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html) . In this answer this is also ignored. – Lorah Attkins Feb 02 '23 at 08:52
-
@LorahAttkins, I presume so that this answer is C-compatible instead of just gcc-compatible. From your link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html (emphasis added): "Declaring zero-length arrays is allowed in **GNU** C **as an extension**." So, zero-length arrays aren't C-compatible. They are just gcc C compatible as a gcc extension. C and "GNU C" (AKA "gcc C") aren't _quite_ the same language. I generally program in GNU C, however, not C, so I'd be fine with using that extension, but it must be noted that it is not C compatible. – Gabriel Staples Feb 02 '23 at 16:43
-
@LorahAttkins: The macro only produces a typedef, no actual space is reserved in program. Also see Gabriel's remark on zero length arrays. – Nordic Mainframe Feb 03 '23 at 07:19
cl
I know the question explicitly mentions gcc, but just for completeness here is a tweak for Microsoft compilers.
Using the negatively sized array typedef does not persuade cl to spit out a decent error. It just says error C2118: negative subscript
. A zero-width bitfield fares better in this respect. Since this involves typedeffing a struct, we really need to use unique type names. __LINE__
does not cut the mustard — it is possible to have a COMPILE_TIME_ASSERT()
on the same line in a header and a source file, and your compile will break. __COUNTER__
comes to the rescue (and it has been in gcc since 4.3).
#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond,msg) \
typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \
CTASTR(static_assertion_failed_,__COUNTER__)
Now
STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
under cl
gives:
error C2149: 'static_assertion_failed_use_another_compiler_luke' : named bit field cannot have zero width
Gcc also gives an intelligible message:
error: zero width for bit-field ‘static_assertion_failed_use_another_compiler_luke’

- 14,989
- 3
- 48
- 57
This answer vastly improved Apr. 17 2022, as an Easter gift. I believe it to be the most thorough and complete answer here, since I have produced 3 separate solutions of varying complexities to cover different versions of C and C++, and since the last version I present covers all versions of C and C++, which was initially a seemingly impossible feat.
You can view and test the code below for all versions of C and C++ in my file static_assert_for_all_versions_of_c_and_cpp.c.
Note that C++ style comments are not allowed in ISO C90
, so my code samples must use only C-style comments (/* */
), instead of C++-style //
comments, in order for my code to be able to compile in -std=c90
as well.
Quick summary (TLDR) to obtain STATIC_ASSERT(test_for_true)
:
If you want a quick and super-simple macro to work in any version of C (when compiled with gcc), or in any version of C++ as of C++11 or later, see my two simple chunks of macros in the bottom of the very next section: "Summary of static assert declarations available in C and C++". Here are those macros copied and pasted for your convenience, followed by a more-complicated but universal STATIC_ASSERT(test_for_true)
macro for any version of C or C++. Here are my 3 main solutions:
[the simplest option by far!]
STATIC_ASSERT(test_for_true)
for only C11 or later and only C++11 or later:#include <assert.h> #define STATIC_ASSERT(test_for_true) \ static_assert((test_for_true), "(" #test_for_true ") failed")
Or [MY PREFERENCE],
STATIC_ASSERT(test_for_true)
for any version of C (as a gcc extension when using the gcc compiler), including C90, C99, C11, C17, etc., and for C++11 or later (cannot handle older versions of C++):#ifdef __cplusplus #ifndef _Static_assert #define _Static_assert static_assert #endif #endif #define STATIC_ASSERT(test_for_true) \ _Static_assert((test_for_true), "(" #test_for_true ") failed")
STATIC_ASSERT(test_for_true)
for any version of C and any version of C++:If you want a single
STATIC_ASSERT
macro to work in all versions of C and C++, I present it in the section which begins with "My final version", below. You can see what build commands and language settings I used to test it in the "Summary of tests" section at the bottom. Getting a static assert to work in pre-C++11, such as C++98, C++03, etc, was the hard part! The_Static_assert_hack
macro below is what handles those earlier versions of C++. Here is the full code chunk to handle all versions of C and C++, with most comments removed, for your convenience:// See: https://stackoverflow.com/a/54993033/4561887 #define CONCAT_(prefix, suffix) prefix##suffix #define CONCAT(prefix, suffix) CONCAT_(prefix, suffix) #define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__) /* Static assert hack required for **pre-C++11**, such as C++98, C++03, etc. * - It works only with C++, NOT with C! */ #define _Static_assert_hack(expression, message) \ struct MAKE_UNIQUE_VARIABLE_NAME(static_assertion_failed) \ { \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wunused-local-typedefs\"") \ typedef char static_assertion_failed[(expression) ? 1 : -1]; \ _Pragma("GCC diagnostic pop") \ } /* For C++ only: * See: https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html */ #ifdef __cplusplus #if __cplusplus < 201103L /* for pre-C++11 */ #ifndef _Static_assert #define _Static_assert _Static_assert_hack #endif #else /* for C++11 or later */ #ifndef _Static_assert #define _Static_assert static_assert #endif #endif #endif /* For C **and** C++: */ #define STATIC_ASSERT(test_for_true) \ _Static_assert((test_for_true), "(" #test_for_true ") failed")
Summary of static assert declarations available in C and C++:
Know that for the:
- C language:
_Static_assert(expression, message)
is available in C11 or later.- Per the cppreference.com community wiki link above,
static_assert
is also available as a convenience macro to_Static_assert
, in the header<assert.h>
, in order to match the naming in C++11. So, to get the C++-likestatic_assert
as a macro in C11 or later, you should also#include <assert.h>
. _Static_assert(expression)
(ie: without themessage
part) is also available as of C23 or later.
- Per the cppreference.com community wiki link above,
- C++ language:
static_assert(expression, message)
is available in C++11 or later.static_assert(expression)
(ie: without themessage
part) is also available in C++17 or later.
- gcc compiler:
- As of gcc compiler version 4.6 and later,
_Static_assert
is supported as a gcc extension for all versions of C, including c90, c99, c11, c17, etc.- And, per the C11 standard, as stated above,
static_assert
is avaialable as a macro to_Static_assert
for C11 or later if you also#include <assert.h>
.
- And, per the C11 standard, as stated above,
- As of g++ compiler version 4.3 and later,
static_assert
is supported as a keyword for C++11 or later. You do NOT need to#include <assert.h>
in C++ like you do in C to get this format. - GCC source: https://www.gnu.org/software/gnulib/manual/html_node/assert_002eh.html (emphasis added):
Even-older platforms do not support
static_assert
or_Static_assert
at all. For example, GCC versions before 4.6 do not support_Static_assert
, and G++ versions before 4.3 do not supportstatic_assert
, which was standardized by C11 and C++11.C
_Static_assert
and C++static_assert
are keywords that can be used without including<assert.h>
. The Gnulib substitutes are macros that require including<assert.h>
.- See also: https://gcc.gnu.org/wiki/C11Status --I got this link from the main answer.
- As of gcc compiler version 4.6 and later,
I like to write a STATIC_ASSERT
wrapper macro to reduce the arguments down to 1 and automatically produce the message
argument so I can do STATIC_ASSERT(expression)
instead of STATIC_ASSERT(expression, message)
. Here is how to easily do that:
- For only C11 or later and only C++11 or later:
#include <assert.h> #define STATIC_ASSERT(test_for_true) \ static_assert((test_for_true), "(" #test_for_true ") failed")
- Or [MY PREFERENCE], for any version of C (as a gcc extension when using the gcc compiler), including C90, C99, C11, C17, etc., and for C++11 or later (cannot handle older versions of C++):
#ifdef __cplusplus #ifndef _Static_assert #define _Static_assert static_assert #endif #endif #define STATIC_ASSERT(test_for_true) \ _Static_assert((test_for_true), "(" #test_for_true ") failed")
- For versions of C++ older than C++11, you'll have to use a hack to obtain a functional static assert. Use my pretty intricate pre-C++11 static assert hack presented below, or, (even better!), just upgrade to C++11 or later.
Test the above code snippets here in my static_assert_for_all_versions_of_c_and_cpp.c.
Static assert hacks for non-gcc pre-C11, and for pre-C++11
1/2. For C only (ex: useful for non-gcc pre-C11)
For gcc pre-C11, gcc has already defined _Static_assert(expression, message)
, which is really nice. So, just use that and be done, as described above! But, what if you aren't using the gcc compiler though? What can you do?
Well, I noticed something really interesting. If I use _Static_assert(1 > 2, "this should fail");
in C90 with gcc, using this build command:
gcc -Wall -Wextra -Werror -O3 -std=c90 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
I get this compile-time error for that failed _Static_assert
. This is a super weird error! This is not an accidental build error though, this is the static assert failure error, because they are also using a hack for this version of C to get compile-time static assertions!
In file included from /usr/include/features.h:461,
from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
from /usr/include/stdint.h:26,
from /usr/lib/gcc/x86_64-linux-gnu/9/include/stdint.h:9,
from static_assert_for_all_versions_of_c_and_cpp.c:73:
static_assert_for_all_versions_of_c_and_cpp.c: In function ‘main’:
static_assert_for_all_versions_of_c_and_cpp.c:224:5: error: negative width in bit-field ‘__error_if_negative’
224 | _Static_assert(1 > 2, "this should fail");
| ^~~~~~~~~~~~~~
If I go to the gcc source code mirror on GitHub here (https://github.com/gcc-mirror/gcc), clone the repo, and then search for __error_if_negative
using grep or ripgrep I find a result in only one location, here: https://github.com/gcc-mirror/gcc/blob/master/libgcc/soft-fp/soft-fp.h#L69-L71:
# define _FP_STATIC_ASSERT(expr, msg) \
extern int (*__Static_assert_function (void)) \
[!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]
This is a static assertion hack you can borrow and use in non-gcc versions of pre-C11 C!
Just replace _FP_STATIC_ASSERT
with _Static_assert
, like this:
# define _Static_assert(expr, msg) \
extern int (*__Static_assert_function (void)) \
[!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]
Caveats of using the _Static_assert
hack just above:
- It only works in C, not in C++!
- It does not work inside structs or unions in ISO C--ie: when you use
-std=c90
,-std=c99
, etc.- It does work, I believe, if you use the gnu C language, such as
-std=gnu90
or-std=gnu99
, however. - If you try to use it inside a union or struct like this:
...then you'll see this super cryptic error abouttypedef union data_u { data_t data; uint8_t bytes[sizeof(data_t)]; _Static_assert(2 > 1, "this should pass"); _Static_assert(5 > 4, "this should pass"); } data_union_t;
expected specifier-qualifier-list before ‘extern’
. This is not because the static assertion expression failed (was false), but rather it is because the static assertion hack is broken in this use-case. Notice thatextern
is used in the hack above, so, it shows up in the error:eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=c90 static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a In file included from /usr/include/features.h:461, from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33, from /usr/include/stdint.h:26, from /usr/lib/gcc/x86_64-linux-gnu/9/include/stdint.h:9, from static_assert_for_all_versions_of_c_and_cpp.c:73: static_assert_for_all_versions_of_c_and_cpp.c:193:5: error: expected specifier-qualifier-list before ‘extern’ 193 | _Static_assert(2 > 1, "this should pass"); | ^~~~~~~~~~~~~~
- It does work, I believe, if you use the gnu C language, such as
2/2. For C++ only (ex: useful for pre-C++11)
I found it very tricky to get a nice static assertion hack working in pre-C++11 C++, but I got one working! It's quite the work-of-art, but it does appear to work, to work well, and to be robust. It also does work inside structs and unions just like C++11's static_assert
does! Here it is. You can test it here in my static_assert_for_all_versions_of_c_and_cpp.c:
#define CONCAT_(prefix, suffix) prefix##suffix
#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)
#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
/* Static assert hack required for **pre-C++11**, such as C++98, C++03, etc. */
/* - It works only with C++, NOT with C! */
#define _Static_assert_hack(expression, message) \
struct MAKE_UNIQUE_VARIABLE_NAME(static_assertion_failed) \
{ \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wunused-local-typedefs\"") \
typedef char static_assertion_failed[(expression) ? 1 : -1]; \
_Pragma("GCC diagnostic pop") \
}
My final version: a single STATIC_ASSERT()
which works with all versions of C and all versions of C++, when compiled with gcc
With just a few tweaks to change which style is used and when, the below code could be made to work with any version of C and C++ on non-gcc compilers, too.
As it is written, I expect it to work for all versions of C and gnu C and all versions of C++ and gnu++ when compiled with either the gcc/g++ compiler or the LLVM clang compiler.
Here is the final version: one static assert to handle any version of C or C++!:
/* --------------------------------- START ---------------------------------- */
/* OR [BEST], for **any version of C OR C++**: */
/* See: https://stackoverflow.com/a/71899854/4561887 */
#define CONCAT_(prefix, suffix) prefix##suffix
/* Concatenate `prefix, suffix` into `prefixsuffix` */
#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)
/* Make a unique variable name containing the line number at the end of the */
/* name. Ex: `uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0;` would */
/* produce `uint64_t counter_7 = 0` if the call is on line 7! */
#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
/* Static assert hack required for **pre-C++11**, such as C++98, C++03, etc. */
/* - It works only with C++, NOT with C! */
/* See: */
/* 1. [my ans with this] https://stackoverflow.com/a/54993033/4561887 */
/* 1. Info. on `_Pragma()`: https://stackoverflow.com/a/47518775/4561887 */
/* 1. The inspiration for this `typedef char` array hack as a struct */
/* definition: https://stackoverflow.com/a/3385694/4561887 */
/* Discard the `message` portion entirely. */
#define _Static_assert_hack(expression, message) \
struct MAKE_UNIQUE_VARIABLE_NAME(static_assertion_failed) \
{ \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wunused-local-typedefs\"") \
typedef char static_assertion_failed[(expression) ? 1 : -1]; \
_Pragma("GCC diagnostic pop") \
}
/* For C++ only: */
/* See: https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html */
#ifdef __cplusplus
#if __cplusplus < 201103L
/* for pre-C++11 */
#ifndef _Static_assert
#define _Static_assert _Static_assert_hack
#endif
#else
/* for C++11 or later */
#ifndef _Static_assert
#define _Static_assert static_assert
#endif
#endif
#endif
/* For C **and** C++: */
#define STATIC_ASSERT(test_for_true) \
_Static_assert((test_for_true), "(" #test_for_true ") failed")
/* ---------------------------------- END ----------------------------------- */
The references I used to help me build this up are in the comments in the source code above. Here are the clickable links copied from there:
- [my answer] How to auto-generate unique variable names with the line number in them by using macros
- I learned this primarily from @Jarod42 here, but also from @Adam.Rosenfield here.
- Info. on
_Pragma()
: How to disable GCC warnings for a few lines of code - The inspiration for this
typedef char
array hack as a struct definition: - gcc predefined macros:
C++03 sample static assert error output:
Using the above STATIC_ASSERT
in a pre-C++11 use-case, here is some sample code with a static assert which is expected to fail since it is false:
typedef union data_u
{
data_t data;
uint8_t bytes[sizeof(data_t)];
STATIC_ASSERT(2 > 2); /* this should fail */
} data_union_t;
Here is what the build command and failing output looks like. It's a bit of a mouthful of errors for one failed static assert in C++, but this is to be expected for hacks like this, and the gcc C90 hack for _Static_assert
, presented previously above, wasn't any better:
eRCaGuy_hello_world/c$ g++ -Wall -Wextra -Werror -O3 -std=c++03 static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
static_assert_for_all_versions_of_c_and_cpp.c:129:67: error: narrowing conversion of ‘-1’ from ‘int’ to ‘long unsigned int’ is ill-formed in C++11 [-Werror=narrowing]
129 | typedef char static_assertion_failed[(expression) ? 1 : -1]; \
| ^
static_assert_for_all_versions_of_c_and_cpp.c:139:36: note: in expansion of macro ‘_Static_assert_hack’
139 | #define _Static_assert _Static_assert_hack
| ^~~~~~~~~~~~~~~~~~~
static_assert_for_all_versions_of_c_and_cpp.c:151:5: note: in expansion of macro ‘_Static_assert’
151 | _Static_assert((test_for_true), "(" #test_for_true ") failed")
| ^~~~~~~~~~~~~~
static_assert_for_all_versions_of_c_and_cpp.c:187:5: note: in expansion of macro ‘STATIC_ASSERT’
187 | STATIC_ASSERT(2 > 2);
| ^~~~~~~~~~~~~
static_assert_for_all_versions_of_c_and_cpp.c:129:59: error: size ‘-1’ of array ‘static_assertion_failed’ is negative
129 | typedef char static_assertion_failed[(expression) ? 1 : -1]; \
| ~~~~~~~~~~~~~^~~~~~~~
static_assert_for_all_versions_of_c_and_cpp.c:139:36: note: in expansion of macro ‘_Static_assert_hack’
139 | #define _Static_assert _Static_assert_hack
| ^~~~~~~~~~~~~~~~~~~
static_assert_for_all_versions_of_c_and_cpp.c:151:5: note: in expansion of macro ‘_Static_assert’
151 | _Static_assert((test_for_true), "(" #test_for_true ") failed")
| ^~~~~~~~~~~~~~
static_assert_for_all_versions_of_c_and_cpp.c:187:5: note: in expansion of macro ‘STATIC_ASSERT’
187 | STATIC_ASSERT(2 > 2);
| ^~~~~~~~~~~~~
cc1plus: all warnings being treated as errors
Summary of tests
See static_assert_for_all_versions_of_c_and_cpp.c.
The final STATIC_ASSERT(test_for_true)
macro I present just above, which handles all versions of C and C++, was tested on Linux Ubuntu 20.04 with gcc compiler version (gcc --version
) 9.4.0
(gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
).
Here are the various build commands and languages for which it is tested and works. Again, out of all of these versions, the only ones which do not allow the STATIC_ASSERT()
macro to be used inside of structs and unions are -std=c90
and -std=c99
! All of the other options support the usage of STATIC_ASSERT
wherever you want, including outside of functions, inside of functions, and inside of structs and unions.
# -------------------
# 1. In C:
# -------------------
gcc -Wall -Wextra -Werror -O3 -std=c90 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
gcc -Wall -Wextra -Werror -O3 -std=c99 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
gcc -Wall -Wextra -Werror -O3 -std=c11 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
gcc -Wall -Wextra -Werror -O3 -std=c17 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
# gnu C
gcc -Wall -Wextra -Werror -O3 -std=gnu90 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
gcc -Wall -Wextra -Werror -O3 -std=gnu99 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
gcc -Wall -Wextra -Werror -O3 -std=gnu11 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
# [my default C build cmd I use today]:
gcc -Wall -Wextra -Werror -O3 -std=gnu17 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a
# -------------------
# 2. In C++
# -------------------
g++ -Wall -Wextra -Werror -O3 -std=c++98 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
g++ -Wall -Wextra -Werror -O3 -std=c++03 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
g++ -Wall -Wextra -Werror -O3 -std=c++11 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
g++ -Wall -Wextra -Werror -O3 -std=c++17 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
# gnu++
g++ -Wall -Wextra -Werror -O3 -std=gnu++98 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
g++ -Wall -Wextra -Werror -O3 -std=gnu++03 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
g++ -Wall -Wextra -Werror -O3 -std=gnu++11 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
# [my default C++ build cmd I use today]:
g++ -Wall -Wextra -Werror -O3 -std=gnu++17 \
static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a
Related:

- 36,492
- 15
- 194
- 265
-
1Why so complicated, when there is a `static_assert` macro in `assert.h`? – Kami Kaze Sep 05 '19 at 09:03
-
@KamiKaze, I'm surprised by your question, as it seems like you may not have actually read my answer? The 2nd line of my answer says it all: "static_assert() is defined in C++11 and later". Therefore, `static_assert()` isn't available at all in C. See here also: https://en.cppreference.com/w/cpp/language/static_assert --it shows `static_assert` exists "(since C++11)". The beauty of my answer is that it works in gcc's C90 and later, as well as any C++11 and later, instead of just in C++11 and later, like `static_assert()`. Also, what's complicated about my answer? It's only a couple `#define`s. – Gabriel Staples Sep 05 '19 at 21:04
-
1`static_assert`is defined in C since C11. It is a macro that expands to `_Static_assert`. https://en.cppreference.com/w/c/error/static_assert . Additionally and contrast to your answer `_Static_assert` is not available in c99 and c90 in gcc (only in gnu99 and gnu90). This is compliant to the standard. Basically you do a lot of extra work, that only brings benefit if compiled with gnu90 and gnu99 and which makes the actual usecase insignificantly small. – Kami Kaze Sep 06 '19 at 07:30
-
> "_Static_assert is not available in c99 and c90 in gcc (only in gnu99 and gnu90)". I see what you mean. It is a gcc extension so you are correct. > "Basically you do a lot of extra work". I disagree; 2 extremely simple defines is by no means "a lot" of extra work. That being said, I see what you mean now. I still think what I've done is useful and adds value to the body of knowledge and answers presented here, so I don't think it merits the downvote. Also, my mistake in saying "C90 and later" instead of "gcc C90 and later", or "g90 and later", was only in my comment above, not in my answer. – Gabriel Staples Sep 06 '19 at 15:55
-
As it was factually wrong, a downvote was justified. If you would correct the wrong statements I will check the answer again and may retract my downvote. Still adding such code if not necessary (so if you do not work with gnu90 and gnu99) is not benefical for clarity and adds more clutter. If you have the usecase it might be worth it. But I wonder about the rarity of the usecase of where gnu99/90 and c++11 compability is required. – Kami Kaze Sep 09 '19 at 06:06
-
1Okay I see that I was mistaken to some degree `_Static_assert` is defined in c90/c99 of gcc, the "problem" is that it works different then in c11. It seems to be similar to what Paolo.Bolzoni presented in his answer as it speaks about negative bitfields. You could clarify that ( I need an edit on the answer to retract the DV) – Kami Kaze Sep 09 '19 at 06:16
-
@KamiKaze, if you're interested, I just massively rewrote and improved my answer. I finally have produced a single `STATIC_ASSERT()` macro which works in _all_ versions of C and C++ now (tested with gcc compiler)! The big breakthrough for me was coming up with a static assert which would work in C++ pre-C++11, as that was the missing gap prior to my latest discoveries. – Gabriel Staples Apr 17 '22 at 21:06
From Wikipedia:
#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}
COMPILE_TIME_ASSERT( BOOLEAN CONDITION );

- 4,679
- 12
- 41
- 60
-
15It would be better if you linked to the true source: http://www.jaggersoft.com/pubs/CVu11_3.html – Matt Joiner Aug 02 '10 at 06:43
-
It does not work in gcc 4.6 - it says "case label does not reduce to an integer constant". It has a point. – Liosan Dec 12 '13 at 08:47
-
you've both probably moved waaay on by now, but I ended up writing my own (see [my answer](http://stackoverflow.com/questions/3385515/static-assert-in-c/25874285#25874285)). I used your link @MattJoiner to aid me – Hashbrown Sep 16 '14 at 16:51
-
And if you can be bothered, let me know if it works for you, @Liosan. I've only just started delving into C++ so I've come late to the party – Hashbrown Sep 16 '14 at 16:51
-
As for Visual C++, it has **static_assert** built-in since version 2010, and it works in both c++ and c modes. However, it does not have the c99 _Static_assert built-in. – ddbug Oct 05 '16 at 18:19
The classic way is using an array:
char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];
It works because if the assertion is true the array has size 1 and it is valid, but if it is false the size of -1 gives a compilation error.
Most compilers will show the name of the variable and point to the right part of the code where you can leave eventual comments about the assertion.

- 2,416
- 1
- 18
- 29
-
1Wrapping this up into a generic `#define STATIC_ASSERT()` type macro and providing more generic examples and sample compiler output from your generic examples using `STATIC_ASSERT()` would give you a lot more upvotes and make this technique make more sense I think. – Gabriel Staples Mar 05 '19 at 04:17
-
1I don't agree. The compiler sees thought macros and give a more confusing message. – Paolo.Bolzoni Mar 17 '19 at 07:42
-
If using the STATIC_ASSERT() macro with __LINE__
, it is possible to avoid line number clashes between an entry in a .c file and a different entry in a header file by including __INCLUDE_LEVEL__
.
For example :
/* Trickery to create a unique variable name */
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2( X, Y )
#define BOOST_DO_JOIN2( X, Y ) X##Y
#define STATIC_ASSERT(x) typedef char \
BOOST_JOIN( BOOST_JOIN(level_,__INCLUDE_LEVEL__), \
BOOST_JOIN(_assert_on_line_,__LINE__) ) [(x) ? 1 : -1]

- 116
- 1
- 4
I would NOT recommend using the solution using a typedef
:
// Do NOT do this
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
The array declaration with typedef
keyword is NOT guaranteed to be evaluated at compile time. For example, the following code in block scope will compile:
int invalid_value = 0;
STATIC_ASSERT(invalid_value, this_should_fail_at_compile_time_but_will_not);
I would recommend this instead (on C99):
// Do this instead
#define STATIC_ASSERT(COND,MSG) static int static_assertion_##MSG[(COND)?1:-1]
Because of the static
keyword, the array will be defined at compile time. Note that this assert will only work with COND
which are evaluated at compile time. It will not work with (i.e. the compile will fail) with conditions that are based on values in memory, such as values assigned to variables.

- 36,492
- 15
- 194
- 265

- 55
- 2
-
7While this would work, it would also grow your memory requirements. – sherrellbc Mar 01 '19 at 19:19
-
1error: 'static_assertion_INVALID_CHAR_SIZE' defined but not used [-Werror=unused-variable] – Alex D Aug 01 '19 at 22:26
-
The unused variable warning can be turned off with `__attribute__((unused))`. I compared this with the typedef solution and the compiler generates the exact same code, most likely because the variable is not used. So this does not grow memory requirements – MarcH Jun 28 '21 at 05:04
Generic static_assert
( C89, C++98 or later ):
#define CONCAT_(prefix, suffix) prefix##suffix
#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)
#define outscope_assert(expr) \
struct CONCAT(__outscope_assert_, __COUNTER__) \
{ \
char \
outscope_assert \
[2*(expr)-1]; \
\
} CONCAT(__outscope_assert_, __COUNTER__)
call it like this:
outscope_assert( 0 > 5 );
Compatible with C89 :
gcc main.c -o main.exe -std=c89
or C++98 :
g++ main.c -o main.exe -std=c++98
The error that it produces looks like this:
main.c:32:9: error: size of array 'outscope_assert' is negative
32 | outscope_assert \
| ^~~~~~~~~~~~~~~
main.c:50:1: note: in expansion of macro 'outscope_assert'
50 | outscope_assert(2 > 5);
| ^~~~~~~~~~~~~~~
It does not break so easily as most of the other solutions that have been proposed, you can test it!
/* Some test */
/* Global */
outscope_assert(1 < 2);
/* Within Struct */
struct A
{
int a;
outscope_assert(1 < 2);
outscope_assert(2 > 1); outscope_assert(2 > 1); /* Same Line */
};
int main (void)
{
/* Within Function */
outscope_assert(2 > 1);
return 0;
}
About __COUNTER__
:
__COUNTER__
is a macro that monotonically increments is value during compilation (starting from 0) and it is commonly used to generate ids.
The macro may or may not be defined depending on the compiler and/or is version, altough basically all modern compilers support it.
If your are stuck on using some dinosaur or unicorn like compiler, you will have to use an alternative:
- replace
__COUNTER__
with__LINE__
, the catch is that you will no be able anymore to have static asserts on the same line, and you may also have problems having them on the same line in different files. - (prob the best option) replace
__COUNTER__
withmy_id
and add it as parameter in the macro function definition like this:#define outscope_assert(expr, myid)
and then call the macro likeoutscope_assert(0 < 1 , this_is_myid );
- Read the next paragraph we will use an
inscope_assert
(you can skip this) Why inscope_assert
?
#define inscope_assert(expr) \
{ \
char \
inscope_assert \
[2*(expr)-1]; \
(void)inscope_assert; \
}
As you may have noticed, inscope_assert
is pretty the same of outscope_assert
just without the struct
and the id
thing.
This one has obvious disadvantages: it cannot be used neither globally nor within a struct, but well on the flip side if you cannot use the __COUNTER__
you can rest assured this will work without any side-effects and it guarantees the strictest C89 possible.
You may have noticed (prob not) that if we use more strict flags on compilation:
gcc main.c -o main.exe -std=c89 -Wall -Wextra -ansi -pedantic
our outscope_assert
declared in main
get us a warning
:
warning: unused variable '__outscope_assert__9' [-Wunused-variable]
Simply telling us that we have declared a variable of type struct but we not have used it, not a big deal really, but still our inscope_assert
will not produce it.
C11, C23 and GCC Specific
C11 standard adds the _Static_assert keyword. _Static_assert ( expression , message )
C23 standard adds the static_assert keyword static_assert ( expression , message ) or static_assert ( expression )
gcc-4.6 adds the _Static_assert keyword for all versions of C, including c90, c99, c11, c17, etc.
So simply doing some before-checking:
#if !defined static_assert
/* C11 or later */
#if defined _Static_assert
#define static_assert _Static_assert
/* GCC 4.6 or later */
#elif defined __GNUC__ && ( __GNUC__ > 4 || __GNUC__ == 4 && defined __GNUC_MINOR__ && __GNUC_MINOR >= 6)
/* It will work but it will throw a warning:
warning: ISO C90 does not support '_Static_assert' [-Wpedantic]
*/
#define static_assert _Static_assert
#endif
#endif
Quick Technical Explanation:
Unwrapped the macro will look like this:
struct __outscope_assert_24 { char outscope_assert [2*(2 > 1)-1]; } __outscope_assert_25
Our objective is to throw an error if the expression (in this case 2 > 1
) is false:
error: size of array 'outscope_assert' is negative
The expr (2 > 1)
evaluates to 1 because true so 2*1 - 1 = 1
we are declaring an array of char
of size = 1.
The expr (2 > 9)
evaluates to 0 because false so 2*0 - 1 = -1
we are declaring an array of char
of size = -1. Wich trows an error at compile time.
__outscope_assert_24
and __outscope_assert_25
are the struct name and the variable name, omitting the first will cause a warning in g++, Omitting the second will cause a duplicate member error if two assert are declared in the same scope.
The macro CONCAT
and CONCAT_
are here to create the struct and variable names.

- 2,317
- 17
- 31
From Perl, specifically perl.h
line 3455 (<assert.h>
is included beforehand):
/* STATIC_ASSERT_DECL/STATIC_ASSERT_STMT are like assert(), but for compile
time invariants. That is, their argument must be a constant expression that
can be verified by the compiler. This expression can contain anything that's
known to the compiler, e.g. #define constants, enums, or sizeof (...). If
the expression evaluates to 0, compilation fails.
Because they generate no runtime code (i.e. their use is "free"), they're
always active, even under non-DEBUGGING builds.
STATIC_ASSERT_DECL expands to a declaration and is suitable for use at
file scope (outside of any function).
STATIC_ASSERT_STMT expands to a statement and is suitable for use inside a
function.
*/
#if (defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L)) && (!defined(__IBMC__) || __IBMC__ >= 1210)
/* static_assert is a macro defined in <assert.h> in C11 or a compiler
builtin in C++11. But IBM XL C V11 does not support _Static_assert, no
matter what <assert.h> says.
*/
# define STATIC_ASSERT_DECL(COND) static_assert(COND, #COND)
#else
/* We use a bit-field instead of an array because gcc accepts
'typedef char x[n]' where n is not a compile-time constant.
We want to enforce constantness.
*/
# define STATIC_ASSERT_2(COND, SUFFIX) \
typedef struct { \
unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
} _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
# define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
# define STATIC_ASSERT_DECL(COND) STATIC_ASSERT_1(COND, __LINE__)
#endif
/* We need this wrapper even in C11 because 'case X: static_assert(...);' is an
error (static_assert is a declaration, and only statements can have labels).
*/
#define STATIC_ASSERT_STMT(COND) STMT_START { STATIC_ASSERT_DECL(COND); } STMT_END
If static_assert
is available (from <assert.h>
), it is used. Otherwise, if the condition is false, a bit-field with a negative size is declared, which causes compilation to fail.
STMT_START
/ STMT_END
are macros expanding to do
/ while (0)
, respectively.

- 84,125
- 8
- 85
- 148
For those of you wanting something really basic and portable but don't have access to C++11 features, I've written just the thing.
Use STATIC_ASSERT
normally (you can write it twice in the same function if you want) and use GLOBAL_STATIC_ASSERT
outside of functions with a unique phrase as the first parameter.
#if defined(static_assert)
# define STATIC_ASSERT static_assert
# define GLOBAL_STATIC_ASSERT(a, b, c) static_assert(b, c)
#else
# define STATIC_ASSERT(pred, explanation); {char assert[1/(pred)];(void)assert;}
# define GLOBAL_STATIC_ASSERT(unique, pred, explanation); namespace ASSERTATION {char unique[1/(pred)];}
#endif
GLOBAL_STATIC_ASSERT(first, 1, "Hi");
GLOBAL_STATIC_ASSERT(second, 1, "Hi");
int main(int c, char** v) {
(void)c; (void)v;
STATIC_ASSERT(1 > 0, "yo");
STATIC_ASSERT(1 > 0, "yo");
// STATIC_ASSERT(1 > 2, "yo"); //would compile until you uncomment this one
return 0;
}
Explanation:
First it checks if you have the real assert, which you would definitely want to be using if it's available.
If you don't it asserts by getting your pred
icate, and dividing it by itself. This does two things.
If it's zero, id est, the assertion has failed, it will cause a divide by zero error (the arithmetic is forced because it is trying to declare an array).
If it is not zero, it normalises the array size to 1
. So if the assertion passed, you wouldn't want it to fail anyway because your predicate evaluated to -1
(invalid), or be 232442
(massive waste of space, IDK if it would be optimised out).
For STATIC_ASSERT
it is wrapped in braces, this makes it a block, which scopes the variable assert
, meaning you can write it many times.
It also casts it to void
, which is a known way to get rid of unused variable
warnings.
For GLOBAL_STATIC_ASSERT
, instead of being in a code block, it generates a namespace. Namespaces are allowed outside of functions. A unique
identifier is required to stop any conflicting definitions if you use this one more than once.
Worked for me on GCC and VS'12 C++

- 12,091
- 8
- 72
- 95
-
2
-
ah, whoops, misread the question. Looks like I came here looking for an answer to C++ anyway (looking at the last line of my answer), so I'll leave it here in case others do the same – Hashbrown Nov 08 '16 at 04:05
This works, with "remove unused" option set. I may use one global function to check global parameters.
//
#ifndef __sassert_h__
#define __sassert_h__
#define _cat(x, y) x##y
#define _sassert(exp, ln) \
extern void _cat(ASSERT_WARNING_, ln)(void); \
if(!(exp)) \
{ \
_cat(ASSERT_WARNING_, ln)(); \
}
#define sassert(exp) _sassert(exp, __LINE__)
#endif //__sassert_h__
//-----------------------------------------
static bool tab_req_set_relay(char *p_packet)
{
sassert(TXB_TX_PKT_SIZE < 3000000);
sassert(TXB_TX_PKT_SIZE >= 3000000);
...
}
//-----------------------------------------
Building target: ntank_app.elf
Invoking: Cross ARM C Linker
arm-none-eabi-gcc ...
../Sources/host_if/tab_if.c:637: undefined reference to `ASSERT_WARNING_637'
collect2: error: ld returned 1 exit status
make: *** [ntank_app.elf] Error 1
//

- 1
- 1
This worked for some old gcc. Sorry that I forgot what version it was:
#define _cat(x, y) x##y
#define _sassert(exp, ln)\
extern char _cat(SASSERT_, ln)[1]; \
extern char _cat(SASSERT_, ln)[exp ? 1 : 2]
#define sassert(exp) _sassert((exp), __LINE__)
//
sassert(1 == 2);
//
#148 declaration is incompatible with "char SASSERT_134[1]" (declared at line 134) main.c /test/source/controller line 134 C/C++ Problem

- 1
For C versions older than C11, it is possible to build your own static assert. The following is tested on old versions of GCC.
Of course, if you can use C11, then it makes the best sense to #include <assert.h>
and use static_assert
.
/** @file
* STATIC_ASSERT allows you to do compile time assertions at file scope or in a function.
* @param expr: a boolean expression that is valid at compile time.
* @param msg: a "message" that must also be a valid identifier, i.e. message_with_underscores
*/
#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg) \
(!!sizeof(struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg) \
extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
#define STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */
#define STATIC_ASSERT_ARRAY_LEN(array, len) \
STATIC_ASSERT(sizeof(array)/sizeof(array[0]) == len, array##_wrong_size);
#endif // STATIC_ASSERT_H
The idea is essentially the same as in Hashbrown's answer, except I have the array helper and a special case for gnuc.

- 25,267
- 15
- 124
- 150
Simple: include sys/cdefs.h
ans use _Static_assert
.
I recommend the same approach for C++ and other compilers too.

- 151
- 1
- 3
I'm surprised this one hasn't been mentioned:
#define STATIC_ASSERT(condition, message) ((void)sizeof(char[1 - 2*!(condition)]))
It does have the limitation that you can only use it in function scope, but doesn't have any uniqueness issues like the out of scope options. Also doesn't use any program memory.
Source: https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/

- 8,063
- 8
- 45
- 41