Example of something which is, and is not, a “Constant Expression” in C?

痴心易碎 提交于 2019-11-28 09:18:15

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)];)

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";

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!