views:

359

answers:

5

I would like to initialize an array of structs, with the same element repetitively, ie

struct st ar[] = { {1,2}, {1,2}, {1,2} };

However I do NOT want to run any code for that, I wish that the layout of the memory upon program's execution would be like so, without any CPU instructions involved (it would increase boot time on very slow CPU and relatively large arrays).

This makes sense, when using the array as mini ad-hoc database (maps id to struct) and when one wishes to use a default value to all database values.

My best solution was to use something of the form

#define I {1,2}
struct st ar[SIZE_OF_ARRAY] = { I,I,I };

So that the compiler will warn me if I'm having too much or too little Is. But this is far from ideal.

I think there's no solution for that in ANSI-C, but I thought that maybe there's a macro-abuse, or gcc extension that would do the work. Ideally I would like a standard solution, but even compiler specific ones would suffice.

I thought That I would somehow be able to define a macro recursively so that I(27) would be resolved to 27 {1,2}s, but I don't think that's possible. But maybe I'm mistaken, is there any hack for that?

Maybe inline assemby would do the trick? It would be very easy to define such memory layout with MASM or TASM, but I'm not sure it is possible to embed memory layout instructions within C code.

Is there any linker trick that would lure it to initialize memory according to my orders?

PS I know I can generate automatically C file with some script. Using custom scripts is not desirable. If I'd use a custom script, I'll invent a C-macro REP(count,exp,sep) and would write a mini-C-preprocessor to replace that with exp sep exp sep ... exp {exp appears count time}.

A: 

What you have in the form of Is is the best Standard C can give you. I don't understand how you can be averse to standard initialization code but okay with assembly. Embedding assembly is necessarily a non-standard non-portable mechanism.

The problem with recursive macros is that you would not know where to stop.

dirkgently
As I said, adding initialization code can slow down boot time. However inline ASM is bad, since it's not standard, however it would provide the exact behavior I wish from the code - memory preinitialized.So to sum it up, ASM is nonportable but gives the desired result, initialization code is standard - but gives a different result which is not always acceptable.
Elazar Leibovich
+5  A: 

The easiest way I can think of is to write a script to generate the initialisers that you can include into your C code:

{1,2},
{1,2},
{1,2}

Then in your source:

struct st ar[] = {
    #include "init.inc"
};

You can arrange your Makefile to generate this automatically if you like.

Greg Hewgill
He is talking about C code. Also I don't see how this is any better than having the initializers along with the definition. Finally, I think he wants to have the initializers auto generated based on the size of the array.
dirkgently
This can be automated, as Greg says. Especially if you call the include file init_3.inc for 3 elements, init_17.inc for 17, etc. Then have a makefile rule to build init_<n>.inc for any n, and generate make dependencies with gcc -M or -MM. So the source says "struct st ar[] = { \n #include "init3.inc" \n };", and the rest is automatic.
Steve Jessop
+10  A: 

The boost preprocessor library (which works fine for C) could help.

#include <boost/preprocessor/repetition/enum.hpp>

#define VALUE(z, n, text) {1,2}

struct st ar[] = {
    BOOST_PP_ENUM(27, VALUE, _)
};

#undef VALUE

If you wish to use it, you'll just need the boost/preprocessor directory from boost - it's entirely self contained.

Although, it does have some arbitrary limits on the number of elements (I think it's 256 repetitions in this case). There is an alternative called chaos which doesn't, but it's experimental and will only work for preprocessors that follow the standard precisely (GCC's does).

Daniel James
Yeah, BPP sounds pretty ideal for this thing.
Marcus Lindblom
A good standard solution - thanks.
Elazar Leibovich
+2  A: 

I'm guessing you can, on the file with the array definition, do:

#include "rep_array_autogen.c"
struct st ar[SIZE_OF_ARRAY] = REPARRAY_DATA;

and have your Makefile generate rep_array_autogen.c with a format like

#define SIZE_OF_ARRAY 3
#define REPARRAY_DATA {{1, 2}, {1, 2}, {1, 2}, }

Since rep_array_autogen.c is built on your machine, it would be just as fast as hand-coding it in there.

Tordek
A: 

Elazar,

Can you give data to support your view that pre-initialized data is faster than run-time initialization?

If you are running code on a standard machine with Hard Disk Drive (HDD) and your program resides on the HDD, then the time to copy the data from data section of your binary image to RAM is essentially the same amount of time as using some type of run-time initialization.

Kip Leitner

Kip Leitner
Kip, I will give you the rational now, and the data later.The rational is, with none-preinitialized data the loader copies the binary image, which contains the information as assembly commands (mov ax,Data). and then this assembly commands must be executed again to move Data into the memory. Which means about double work.I'll try to create a micro-benchmark sometimes soon.
Elazar Leibovich