I'm a tad confused between what is and is not a Constant Expression in C, even after much Googleing. Could you provide an example of something which is, and which is not, a Constant Expression in C?
A constant expression can be evaluated at compile time. That means it has no variables in it. For example:
5 + 7 / 3
is a constant expression. Something like:
5 + someNumber / 3
is not, assuming someNumber
is a variable (ie, not itself a compile-time constant).
There is another subtlety to constant expressions. There are some things that are known to the compiler, but cannot be known to the preprocessor.
For example (24*60*60)
can be computed by both, but sizeof struct foo
is only known to the compiler. This distinction can matter if you are trying to verify that a struct
is defined to meet an externally mandated size, or that its members are mapped at externally specified offsets. (This use case often arises when coding device drivers where the struct
describes device registers as layed out in memory space.)
In that instance you cannot simply say #if (sizeof(struct UART) == 12)
because the preprocessor operates at a pass ahead of the compilation and simply cannot know the size of any types. It is, however, a constant expression and would be valid as an initializer for a global variable (e.g. int UARTwords = sizeof(struct UART) / sizeof(short);
), or to declare the size of an array (e.g. unsigned char UARTmirror[sizeof(struct UART)];
)
Any single-valued literal is a constant expression.
3 0.0f '\n'
(String literals are weird, because they're actually arrays. Seems "hello"
isn't really a constant, as it ends up having to be linked and all that, and the address and contents can change at runtime.)
Most operators (sizeof, casts, etc) applied to constants or types are constant expressions.
sizeof(char)
(byte) 15
Any expression involving only constant expressions is itself also a constant expression.
15 + 3
0.0f + 0.0f
sizeof(char)
Any expression involving function calls or non-constant expressions is usually not a constant expression.
strlen("hello")
fifteen + x
Any macro's status as a constant expression depends on what it expands to.
/* Always a constant */
#define FIFTEEN 15
/* Only constant if (x) is
#define htons(x) (( ((x) >> 8) | ((x) << 8) ) & 0xffff)
/* Never constant */
#define X_LENGTH strlen(x)
I originally had some stuff in here about const
identifiers, but i tested that and apparently it doesn't apply in C. const
, oddly enough, doesn't declare constants (at least, not ones "constant" enough to be used in switch
statements). In C++, however, it does.
Another fun little wrinkle: in C, the value of an 'enum' is a constant, but may only be used after the declaration of the 'enum' is complete. The following, for example, is not acceptable in standard C, though it is acceptable in C++:
enum {foo=19, bar, boz=bar+5;};
It could be rewritten:
enum {foo=19, bar}; enum {boz=bar+5;};
though this would end up defining multiple different enumeration types, rather than one which holds all the values.
Also integral character constants
as 'a'
or '\n'
are constants that the compiler recognizes as such. They have type int
.
Nobody seems have mentioned yet another kind of constant expression: address constants. The address of an object with static storage duration is an address constant, hence you can do this kind of thing at file scope:
char x;
char *p = &x;
String literals define arrays with static storage duration, so this rule is also why you can do this at file scope:
char *s = "foobar";