We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi, my question is to ask whether or not it is possible to partially initialize a struct in C language with Keil C166 compiler.
According to C syntax [1], it should be possible to do things like:
struct { int a; int b; int c; } S = { .b = 0, .c = 1, };
In the example above, only the selected members of the structure are given default values, the others are not.
However, the C166 compiler seems not to understand this expression. When compiling, it reports error: MAIN.C(14): error C25: syntax error near '.'
The reason why i am asking this question is because: the Keil compiler by default creates sections ?C_INITSEC and ?C_CLRMEMSEC which store data for START_V2.A66 to clear variables to zero and assign initialized values at CPU start up. So it will save (well, only a little bit) memory in the ?C_INITSEC by inilizing only non-zero varialbes or struct members only.
[1] en.wikipedia.org/.../C_syntax
http://www.keil.com/support/man/docs/c166/c166_xa.htm
C166 is a C90, not C99, compiler.
I think you'll find that is not the version of the 'C' standard supported by Keil C166...
http://www.keil.com/product/isoansi.asp
You should refer to the actual standards rather than rely upon Wikipedia articles...
Thanks, indeed this is only for C99, and the C166 C90 compiler therefore doesn't support it.
Setting aside the issue of C99 vs. C90, I'm afraid you've misunderstood what this actually does.
No, there is no way, even in C99, to initialize only parts of a struct. A struct is always completely initialized, or completely uninitialized. Just because an element is not given an explicit initializer doesn't mean it won't be initialized --- it only means that the initial value is zero.
The situation is not significantly different from "missing" initializer elements at the end of a traditional C90 struct definition:
struct foo {int a; int b; int c;} foo = {3};
'b' and 'c' are initialized to zero by default. And yes, those zeroes will end up in the master copy of initialized data in the program image. To avoid that, parts of the struct would have to be located in different memory locations. That's clearly impossible.
Is that necessarily so?
Isn't it at least conceivable that the compiler might first do a block fill of the entire initialised area with zeros, and store only the non-zero initialisers in its program image?
No, there is no way, even in C99, to initialize only parts of a struct. A struct is always completely initialized, or completely uninitialized.
Thanks, you remind me some basic concepts that I didn't clearly remember by heart.
You don't really need to remember these details by heart - provided you have a suitable reference to hand.
A serious programmer really should have access to the actual standards - and, of course, a good textbook.
Yes, this is exactly what the C166 compiler does. It automatically generates 2 sections ?C_CLRMEMSEC and ?C_INITSEC, and store them in the program image.
The ?C_CLRMEMSEC keeps the info for the blocks of memory to be cleared to 0s, the ?C_INITSEC holds the info for non-zero values to be initalized for variables.
The problem is only for big structures which have 1 or several members to be initialized as non-zero. In such case, if the structure is initialized, a lot of 0s will be saved into ?C_INITSEC which consumes ROM/FLASH space. I am thinking if it is possible to save this memory space.
I think i will split but structures when possible. And write functions to initialize the non-zero members.
I totally agree with you. But unfortunately i didn't start learning C with a good textbook. I was already thinking to rebuild my C reference source set, but the plan went slow ...
The problem is only for big structures which have 1 or several members to be initialized as non-zero.
Let them initialize to zero and have the few non-zero members initialized in an initialization function.
Conceivable --- sure. But it's complex, and risks wasting more space for book-keeping information ("this byte goes to address x, the next 5 bytes go to address y, ...") than is saved by not explicitly holding all the zeroes.
The more typical approach is to have the linker apply a data compression algorithm to the initializer section before placing it into the program image. The start-up code then decompresses that code into RAM. The classic separation into zero-initialized and copy-initialized data sections is a very simple, first step in that direction --- poor man's run-length encoding.
But usually this is only ever done by toolchains for bigger platforms (32-bit and up), where the overhead of the decompression routine doesn't hurt as much as it would on a smaller micro.