I am making a pong clone to test a SDK... It is some years that I don't C.
Anyway, I tried to do this in the const setup phase:
const int SCREEN_W = 480;
const int SCREEN_H = 480;
const int PLAYER_H_WIDTH = 50;
const int PLAYER_H_HEIGHT = 12;
const int BUFFER = 14;
const int LEFT_BUFFER = PLAYER_H_WIDTH+BUFFER;
const int RIGHT_BUFFER = SCREEN_W-LEFT_BUFFER;
except the compiler throws a error at LEFT_BUFFER
and RIGHT_BUFFER
lines, thus making me wonder, why?
If the answer is "because the standard says so" I still want to know why (why the standard says so?)
EDIT because of comments:
haccks noticed that those lines inside a function (like, main(){}) do compile, while on file scope they don't. I also ask, why?
Also the specific GCC (actually MingW) error is: initializer element is not constant
An initializer for an object declared with static storage duration (outside any function, or inside a function with the static
keyword) must be a constant expression, or must contain only constant expressions.
This declaration:
const int PLAYER_H_WIDTH = 50;
does not make PLAYER_H_WIDTH
a constant expression. The keyword const
really doesn't mean "constant" (i.e., able to be evaluated at compile time); it means "read-only".
So when you declare:
const int LEFT_BUFFER = PLAYER_H_WIDTH+BUFFER;
you're trying to initialize LEFT_BUFFER
with a non-constant expression.
Reference: ISO C standard, 2011 edition, section 6.7.9 paragraph 4:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
To illustrate the difference between const
and constant
, this:
const int r = rand();
is a perfectly valid declaration, as long as it's not at file scope. The object (I don't want to call it a "variable") r
is const (i.e., read-only), but not constant (i.e., its value can't be determined at compile time).
That declaration cannot appear outside any function because of C's execution model, which doesn't allow user code to be executed before main
is entered.
C++ does make such objects constant if the initializer is constant and of integer type; C does not. The rule in C++ requires a bit more work by the compiler; it make the determination of whether an object's name is a constant expression dependent on the the form of its initializer. I'm not sure why C hasn't adopted the C++ rule; probably the committee didn't feel it was worthwhile (remember that any new feature imposes a burden on every compiler implementer).
As a workaround, you can either use the preprocessor:
#define PLAYER_H_WIDTH 50
/* ... */
#define LEFT_BUFFER (PLAYER_H_WIDTH+BUFFER)
or you can use a slightly ugly hack with enum
:
enum { PLAYER_H_WIDTH = 50 };
enum { LEFT_BUFFER = PLAYER_H_WIDTH+BUFFER };
The latter works only for constants of type int
. The trick is that an enum
declaration creates an enumeration type, but the enumerators are still of type int
.
Your question title shows that you've been misled by some confusion. It has nothing to do with a + b
or a - b
. You will get the same error if you just do
const int LEFT_BUFFER = BUFFER;
without any +
or -
.
The problem is that none of the names you defined are "constants", meaning that they cannot form constant expressions. For example, SCREEN_W
is not a constant.
In C language the term "constant" applies to literal values (like 42
) and to enum constants. Variables declared as const
are not "constants" in C language. You can call them "const variables" if you want, but you will never be able to use them where true constants are required.
That is just the way it is in C. That is how it has always been in C. If you want to declare a manifest constant in C language, use #define
or enum
. Don't attempt to use const
. const
has some pleasant properties (compared to #define
), but the fact that const
does not produce true constants in C severely limits the usability of const
for declaring manifest constants.
Your original example actually demonstrates the issue. Objects with static storage duration require constant initializers in C. Since your PLAYER_H_WIDTH
, BUFFER
etc. are not constants, you cannot use them as initializers for objects with static storage duration. And, again, the problem has nothing to do with +
or -
, it is present even in
const int LEFT_BUFFER = BUFFER;
declaration.
If you transfer these lines into local scope, your objects will no longer have static storage duration. They will become local variables. The aforementioned restriction does not apply to local variables, which is why your declarations will compile without any problems. However, if you add the keyword static
to the above declarations, the error will reappear even in local scope.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With