Say I have a scenario where I need to ensure that a value used in my code is a compile-time constant (e.g. perhaps a draconian interpretation of P10 rule 2 "fixed loop bounds"). How can I enforce this at the language-level in C?
C supports the notion of integer constant expression at the language-level. It must be possible to work out a way to take advantage of this so that only values complying with this specification can be used in expressions, right? e.g.:
for (int i = 0; i < assert_constant(10); ++i) {...
Some partial solutions that aren't really general enough to be useful in multiple situations:
Bitfields: a classic strategy for implementing
static_assert
in C prior to C11 was to use a bitfield whose value would be illegal when a condition failed:struct { int _:(expression); }
While this could be easily wrapped for use as part of an expression, it isn't general at all - the maximum value of
expression
"[may] not exceed the width of an object of the type that would be specified were the colon and expression omitted" (C11 6.7.2.1), which places a very low portable limit on the magnitude ofexpression
(generally likely to be 64). It also may not be negative.Enumerations: an
enum
demands that any initializing expressions be integer constant expressions. However, anenum
declaration cannot be embedded into an expression (unlike astruct
definition), requiring its own statement. Since the identifiers in the enumerator list are added to the surrounding scope, we also need a new name each time.__COUNTER__
isn't standardized, so there's no way to achieve this from within a macro.Case: again, the argument expression to a
case
line must be an integer constant. But this requires a surroundingswitch
statement. This isn't a whole lot better thanenum
, and it's the kind of thing you don't want to hide inside a macro (since it will generate real statements, even if they're easy for the optimizer to remove).Array declaration: since C99, the array size doesn't even have to be a constant, meaning it won't generate the desired error anyway. It also again is a statement that requires introducing a name into the surrounding scope, suffering from the same problems as
enum
.
Surely there's some way to hide the constant check in a macro that's repeatable, passes the value through (so it can be used as an expression), and doesn't require a statement line or introduce extra identifiers?