I am designing a self-managed memory function. Global variables provide memory space for storing multiple blocks of memory for different purposes. The following code works fine if it is placed in a function, but there will be a compilation error if it is placed outside the function Why does the mem_ctrl initialization have a compilation error?
The specific error message is: MSVC "error C2099: initializer is not a constant"
How to solve it?
Thanks in advance!
typedef struct
{
int *mem_poll;
int block_size;
int block_num;
}T_MEM_CTRL;
char buffer[10000];
#define BUFFER_ADDR (((unsigned int)buffer) + 5)
// n must power of 2
#define BUF_ROUND_UP(x, n) (((x) + (n) - 1UL) & ~((n) - 1UL))
#define BUF_ROUND_UP_64(x) BUF_ROUND_UP(x, 64LL)
#define BUF_ALIGN(addr) BUF_ROUND_UP_64(addr)
T_MEM_CTRL mem_ctrl[2] =
{
// block mem pool1
{
//(int*)(BUFFER_ADDR), // ok
(int*)(BUF_ALIGN(BUFFER_ADDR)), // not ok!!
8,
50
},
// block mem pool2
{
(int*)(BUF_ALIGN(BUFFER_ADDR + 500)), // not ok!!
12,
100
}
};
The long and the short of it is you cannot use complicated expressions involving addresses as an initial value for a static object. The compiler has to be able to represent the expression in the object module, and the rules of the C standard support that. Typically, the field types available in an object module provide for recording fixed values, addresses of named things (typically as an offset within a portion of a program segment), and fixed offsets from addresses of named things, with maybe a few additional variations.
Your expression would require calculation of a bitwise AND
on an address. That operation is not supported for use in object modules, so the compiler cannot create an object module in which the value you want is represented.
The specific rules for this are in C 2024 6.7.11, which says that an initializer for a static object must be constant expressions or string literals, and C 2024 6.6, which specifies what forms of constant expressions must be supported.
It appears you want to make the initial value the next 64-byte boundary after buffer + 5
. If so, you can do that by making buffer
64-byte aligned, as with _Alignas(64) char buffer[100];
, and then using (int *) (buffer + 5)
for the initial value. That might lay out the space differently than your code would, but you do not appear to have controlled for that anyway. (buffer
could start at any offset in your code, so it might or might not be 64-byte aligned, so requiring it to be 64-byte aligned is a subset of the possibilities of your original code.)
Compilers are not required to support that int *
cast in address constants, but they might. If that is a problem in your compiler, you could modify the code to make the mem_poll
member have type char *
or void *
instead of int *
.