@Fessor: We discussed this same issue months ago on the main thread about
CPCtelera (don't know what page at this moment).
SDCC targets embedded devices, and it's binary code is mainly thought to run from ROM. That's the main problem when dealing with global variables and static initializers. All static initializer values have to be stored in the binary (in ROM), but variables cannot be in ROM: they have to be in RAM. Therefore, a piece of code is required to copy initializer values from ROM to RAM before the program starts, to ensure RAM variables have their initial values.
This is nice on an embedded environment with RAM and ROM, but is terrible when you are creating a game that runs entirely from RAM. This behaviour in RAM means:
- Global variables take double space: space to store initializer values and space for variable storage.
- Initializer code takes more space and CPU cycles at the start.
As current version of
CPCtelera is designed to run from RAM, initializer code is not included. Then, global variables are not initialized at the start, to prevent having two copies of them. Proposed solutions to use global variables with initialization are:
- Declare them as constants. Constant values are stored by SDCC only in ROM space, as they shouldn't change. However, as this space in a CPC game will effectively by RAM, you can change them. To change their values, access them through a non-const pointer.
- Declare variables without an initializer. Then, initialize them using your own init functions.
Examples in
CPCtelera use both of these approaches. In your example, you could do this:
#include <cpctelera.h>
#include <stdio.h>
char* const menulist[]={"Journey Onwards ",
" Continue Game ",
"Create Character",
" Options "};
const u8 n_choices=sizeof(menulist)/sizeof(char *);
void main(void) {
u8 i;
for(i=0; i < n_choices; i++)
printf("%s\n\r", menulist[i]);
// Loop forever
while (1);
}
However, I wouldn't use a global constant/variable for the size of menulist. It's nice to have it automatically calculated, but a #define would be generally more efficient (with respect to generated code). Also, using a signed int to store a value which is always positive and smaller than 256 is an overkill (and will cost you space and CPU cycles). it's preferably to use a u8 (unsigned char).
Take into account that "const char*" and "char* const" are not the same. On first case you are telling the compiler that the character string are constant, but the 4 pointers stored in menulist[] are variables (and thus, they end-up uninitialized). In the second case, your code says that pointers are constant, but character strings may be changed.