This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 7 years ago.
The following code wont compile:
const int a = 0;
struct Test
{
int b;
};
static const struct Test test =
{
a
};
Its a cut down example of what I am really trying to do, but what am I doing wrong?
In C89/90 version of C language all aggregate initializers must consist of constants only. In C language terminology a constant of int type is a literal value, like 10, 20u, 0x1 etc. Enum members are also constants. Variables of const int type are not constants in C. You can't use a const int variable in aggregate initializer. (For this reason, in C language, when you need to declare a named constant you should use either #define or enum, but not const qualifier.)
In C99 this requirement for aggregate initializers was relaxed. It is now OK to use non-constants in aggregate initializers of local objects. However, for static objects (as in your example) the requirement still holds. So, even in C99 you'l' have to either use
#define a 0
or use a named enum constant as suggested in #R..'s answer.
a is not a constant expression. It's a const-qualified variable. If you want a symbolic name that you can use in constant expressions, you need either a preprocessor macro (#define a 0) or an enum (enum { a = 0 };).
Related
I'm trying to pass values of two variables to be the dimension of the students_grades_db array, but it doesn't work and I don't know why, as both are constant variables.
const int number_students = 4;
const int number_of_notes = 4;
float students_grades_db[number_students][number_of_notes] = {0};
It doesn't work :(
A global array declaration must have constant expressions for index sizes. References to variables (even const variables) are not constant expressions, so can't be used.
You can instead use preprocessor macros that expand to constant literals:
#define number_of_students 4
#define number_of_notes 4
If you declare an array outside a function at file scope, it will then get static storage duration. All variables with static storage duration must have compile-time constants as initializers and if they are arrays, the array sizes must also be compile-time constants.
This means that the size has to be something like an integer constant 123 or an expression containing only integer constants.
The const keyword, non-intuitively, does not make something a compile-time constant, it only makes something read-only. C and C++ are different here, you code would work in C++.
Possible solutions:
Move students_grades_db inside a function. Then you can declare array sizes using any kind of expression, including common int variables. You probably shouldn't declare that array as "global" anyhow.
Or swap out your constants for #define number_students 4.
I am actualy using something like this to make constansts for my error function. Is this fine or should I do this somehow else?
// declares 1 and 0 as a FALSE and TRUE
#define TRUE 1
#define FALSE !TRUE
// declares "error types"
const enum {
SYNTAX = 0,
ZERO_OPERATOR = 1,
ZERO_MINUS = 2
};
How I am using "error types" constants in code:
If (!something) error(SYNTAX); // there is a switch in error function which prints the error
There are several different ways to define symbolic constants in C:
Using the preprocessor: #define FOO something
Using enumeration constants: enum { FOO=1, BAR=10, BLETCH=100 };
Using const-qualified variables: const double PI=3.14159265359;
Each has its pros and cons.
Preprocessor macros are basically just text replacements, and can be used for simple values:
#define FOO 10
#define STR "This is a test"
#define PI 3.14159265359
or for more complex expressions
#define BAR (FOO * PI + BLETCH)
The problem is that preprocessor macros are replaced during the preprocessing stage, so after your code is compiled the symbols FOO, STR, PI, and BAR no longer exist (which can make assembly-level debugging difficult), and they don't obey scoping rules (i.e., if you create the macro within a function, it's visibility won't be limited to just that function, it will be visible to any code following the function definition).
You can use enumeration constants for integer values:
enum { FOO = 1, BAR = 10, BLETCH = 100 };
These are not replaced after preprocessing, so they're visible in debuggers. Values are known at compile time, so they can be used for array sizes or cases in switch statements. Enumeration constants occupy the same name space as variable and function names, so you can't use the same symbol for an enumeration constant and a variable. Enumeration constants do obey scoping rules; if you define the enum type within a function, those enumeration constants will not be visible outside of the function body.
You cannot use enumeration constants for non-int values (strings, floats, any integer value wider than int).
You can use const-qualified variables:
const double PI = 3.14159265359;
const char * const STR = "This is a string constant";
const int FOO = 10;
Almost as flexible as preprocessor macros, symbols aren't replaced by the preprocessor. Like enumeration constants, variables obey scoping rules. Downside is that storage must be allocated for all these objects at runtime, and they don't count as compile-time constants, meaning they can't be used for things like cases in a switch statement.
No one scheme is always "best"; it really depends on what you need.
For my part, I use the enum method for related integer constants (error codes, machine states, etc.), and const-qualified variables for just about everything else. I rarely use preprocessor macros for symbolic constants.
I am creating an array on stack as
static const int size = 10;
void foo() {
..
int array[size];
..
}
However, I get the compile error: "expression must have a constant value", even though size is a constant. I can use the macro
#define SIZE (10)
But I am wondering why size marked const causes compilation error.
In C language keyword const has nothing to do with constants. In C language, by definition the term "constant" refers to literal values and enum constants. This is what you have to use if you really need a constant: either use a literal value (define a macro to give your constant a name), or use a enum constant.
(Read here for more details: Shall I prefer constants over defines?)
Also, in C99 and later versions of the language it possible to use non-constant values as array sizes for local arrays. That means that your code should compile in modern C even though your size is not a constant. But you are apparently using an older compiler, so in your case
#define SIZE 10
is the right way to go.
The answer is in another stackoverflow question, HERE
it's because In C objects declared with the const modifier aren't true
constants. A better name for const would probably be readonly - what
it really means is that the compiler won't let you change it. And you
need true constants to initialize objects with static storage (I
suspect regs_to_read is global).
if you are on C99 your IDE compiler option may have a thing called variable-length array (VLA) enable it and you won't get compile error, efficiently without stressing your code though is with MALLOC or CALLOC.
static const int size = 10;
void foo() {
int* array;
array = (int *)malloc(size * sizeof(int));
}
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.
C's constant is not actually a "constant" as we expected. It is an indicator to the compiler that the variable's content could not be changed. The initialize needs to be constant expressions or string literals.
The closest thing to a constant in C is using enum or #define, e.g.
enum {
SCREEN_W = 480,
SCREEN_H = 480,
PLAYER_H_WIDTH = 50,
PLAYER_H_HEIGHT = 12,
BUFFER = 14,
LEFT_BUFFER = PLAYER_H_WIDTH+BUFFER,
RIGHT_BUFFER = SCREEN_W-LEFT_BUFFER
};
I would use enum as far as I could.
use The #define directive preprocessor if you want to avoid this error !
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;
#define LEFT_BUFFER PLAYER_H_WIDTH + BUFFER
#define RIGHT_BUFFER SCREEN_W - LEFT_BUFFER
The #define directive is a preprocessor directive; the preprocessor replaces those macros by their body before the compiler even sees it. Think of it as an automatic search and replace of your source code.
But a constant defined with the const qualifier is best thought of as an unmodifiable variable. It has all the properties of a variable: it has a type, it has a size, it has linkage, you can take its address.
for this the compiler can't compile the assignment of const variable to another, because the assigned variable is not a constant expression.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
“static const” vs “#define” in c
I am going through the K&R book and this question came up. How to best decide whether something should be its own variable or be defined as a symbolic constant?
Suppose we're dealing with const int myNumber = 12; , which also can be #define MY_NUMBER 12 is there a rule of thumb one should follow when deciding which whether a variable needs to be created or symbolic constant used?
The real question is whether n should be a declared const object or a macro. (The question's title currently refers to "a variable or a symbolic constant".)
This:
const int myNumber = 12;
makes myNumber const but not constant. The const keyword means that you're not allowed to modify the object it applies to, but it doesn't make it constant. Switch labels, for example, must be constant; you can't write:
switch (n) {
case myNumber:
...
}
So if you need to use myNumber in a context that requires a constant expression, the above isn't going to work.
On the other hand, a macro:
#define MY_NUMBER 12
means that any use of MY_NUMBER is replaced by a literal 12, which is constant. A drawback of macros is that they're not scoped the way declared objects are; the name MY_NUMBER is visible from the definition to the end of the source file, which can cause conflicts. (Note that macro names are conventionally written in all-caps, specifically to draw attention to them.) In effect, the preprocessor, which is where macros are handled is another language tacked onto C.
For constants of type int, there's another trick you can use (I don't think K&R mention this):
enum { myNumber = 12 };
This creates an anonymous enumeration type, which you aren't actually going to use. myNumber is actually of type int, not of the enumeration type, and you can use it the same way you'd use the literal 12. You can even use an expression to define its value, as long as the expression is constant:
enum { myNumber = 3 * 4 };
(C++ has different rules. In C++, const int myNumber = 12; does make myNumber a constant expression -- and enumeration constants are of the enumerated type, not of type int.)
If you're hard-coding a constant like "2" ... then it's a candidate for symbolic parameter.
ADDENDUM:
You changed the question :)
Q: I am going through the K&R book and this question came up. How to
best decide whether something should be its own variable or be defined
as a symbolic parameter?
A: "Magic numbers" are bad. Use "#define SOME_MEANINGFUL_NAME 2" in preference to "2".
Q: Suppose were dealing with const int myNumber = 12; , which also can
be #define MY_NUMBER 12 is there a rule of thumb one should follow
when deciding which approach to take here?
A: If you're using C++ or C#, then you should probably use "const" in favor of "#define".