Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaration of an array of constants

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.

like image 426
T. Tournesol Avatar asked Mar 23 '16 15:03

T. Tournesol


People also ask

How do you declare an array constant?

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.

How do you declare an array constant in C++?

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

Can an array be a constant C#?

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.

What do you mean by constant array explain with Example C?

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


2 Answers

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.)

like image 167
Nate Eldredge Avatar answered Oct 07 '22 07:10

Nate Eldredge


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

like image 32
Erik Nyquist Avatar answered Oct 07 '22 07:10

Erik Nyquist