I have that may be a problem of declaration :
I declare an array of const int :
const int my_array[] = {
// data...
}
Then I need to declare another array of bytes of the form :
00 aa 01 bb 02 cc
where aabbcc is the 24-bits address in memory of the const int (I precise I code for a very particular platform, this explains that), so I wrote :
const char my_other_array[] = {
00, (my_array >> 16) & 0xFF, 01, (my_array >> 8) & 0xFF, 02, my_array & 0xFF
}
but I get this error :
error: invalid operands to binary >>
error: initializer element is not constant
I thought about casting my_array :
const char my_other_array[] = {
00, (((const u32) my_array) >> 16) & 0xFF, 01, (((const u32) my_array) >> 8) & 0xFF, 02, ((const u32) my_array) & 0xFF
}
but then I get a warning + error :
warning: initializer element is not computable at load time
error: initializer element is not computable at load time
What am I doing wrong ?
Here's the actual code, for those asking (I cut the irrelevant parts) :
#include <genesis.h>
#include "snake.h"
const u32 snake_patterns[] = {
0x00024666,
// ... some 100ths of lines
};
const u16 temp[] = {
1, 0x9370, 0x9400, ((const u32) snake_patterns) & 0xFF, (((const u32) snake_patterns) >> 8) & 0xFF, (((const u32) snake_patterns) >> 16) & 0xFF
};
You'll notice things are a little more complicated, but I think the previous basic example (fixed with the appropriate brackets) shows the problem in a clearer way. Some may recognize a list of DMA calls for the Genesis VDP.
In C#, use readonly to declare a const array. public static readonly string[] a = { "Car", "Motorbike", "Cab" }; In readonly, you can set the value at runtime as well unlike const.
In C++, the most common way to define a constant array should certainly be to, erm, define a constant array: const int my_array[] = {5, 6, 7, 8};
User-defined types, including classes, structs, and arrays, cannot be const . Use the readonly modifier to create a class, struct, or array that is initialized one time at run time (for example in a constructor) and thereafter cannot be changed. C# does not support const methods, properties, or events.
An array is declared as datatype name [ constant-size ] and groups one or more instances of a datatype into one addressable place. constant-size may be an expression, but the expression must evaluate to a constant, like: #define MAX_SIZE 16 ... int list[MAX_SIZE + 1];
The elements you use to initialize your arrays need to be constant expressions. These are defined in Section 6.6 of the C99 standard or the same place in C11. See paragraph 7:
More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
- an arithmetic constant expression,
- a null pointer constant,
- an address constant, or
- an address constant for an object type plus or minus an integer constant expression.
Now my_array
is an address constant, but all you're allowed to do to it is add or subtract an integer constant. By shifting or masking, you're creating something that is no longer a constant expression, thus not allowable in an initializer.
I guess the rationale for this restriction is that C is intended to be usable for relocatable code, where the program's location in memory may not be known until it's loaded in preparation for execution. On such a system, references to addresses within the program have to be filled in by the loader, based on a table within the binary that it reads at load time (e.g. "At relative address 0x12345678 within the program, fill in the absolute address of the object my_array
once it is known"). This table usually has a fairly restrictive format, and probably has a way to express constant offsets ("fill in the absolute address of the object my_array
, plus 42") but typically won't support arbitrary arithmetic.
Probably the simplest solution for you is to make my_other_array
not be const
and fill it in at runtime, by writing a function that extracts the necessary bits of the address of my_array
and inserts them into my_other_array
, and call this function before you need to use my_other_array
.
If it's important for some reason that my_other_array
be already filled in when the program is loaded, and your target platform is such that you know where in memory the program will be located, then you might be able to use the facilities of your assembler or linker to achieve what you want. But of course this would be system-specific.
(Edit: You've mentioned in another comment that this array needs to go in ROM. If so, then I think my last suggestion is your only hope. You may want to post another question about how / whether you can do this with the particular toolchain you're using.)
"What am I doing wrong?"
The most immediate thing I see is....
this is not an array:
const int my_array = { /* elements */ }
this is an array:
const int my_array[N] = { /* N elements */ };
Additionally, don't ignore that error message! it speaks truth!
error: initializer element is not constant
You are using something that is not a constant, namely "my_array", to initialise array elements. "my_array" will evaluate to a pointer to the first element of the array, and this value is not known at compile time.
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