By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,182 Members | 1,400 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,182 IT Pros & Developers. It's quick & easy.

static (non-zero) initialization of an array of structs (array of length #define LEN)

P: n/a
Hello!

In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?

struct mystruct {
int a;
char b;
};

#define STRUCT_INIT {5, 'a'}

#define LEN 3
struct mystruct arr[LEN] = \
{STRUCT_INIT};
/* does not work: only 1st element initialized as desired */

/*
I don not want to write
{STRUCT_INIT, STRUCT_INIT, STRUCT_INIT};
since LEN can change!
!!!!!!!!!
*/

..
..
Can this be done?

Thanks
-Albert

..
..
..
..

/****** test-program ******/
#define <stdio.h>
int main(void)
{
int i;

for (i = 0; i < LEN; i++)
printf("|%d|, |%c|\n", arr[i].a, arr[i].b);
return 0;
}

Aug 27 '07 #1
Share this Question
Share on Google+
23 Replies


P: n/a
On Aug 27, 1:02 pm, anon.a...@gmail.com wrote:
Hello!

In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?

struct mystruct {
int a;
char b;

};

#define STRUCT_INIT {5, 'a'}

#define LEN 3
struct mystruct arr[LEN] = \
{STRUCT_INIT};
/* does not work: only 1st element initialized as desired */

/*
I don not want to write
{STRUCT_INIT, STRUCT_INIT, STRUCT_INIT};
since LEN can change!
!!!!!!!!!
*/
Perhaps it can be done with the preprocessor.
I gave it a try, but I'm no preprocessor expert - the code below
results in compiler (preprocessor) errors.

But: Could something along these lines, be done:
#define STRUCT_INIT {5, 'a'}

#define PUT_A(n) \
#if ((n) == 1) \
STRUCT_INIT \
#elif ((n) 0) \
STRUCT_INIT , PUT_B((n)-1) \
#endif

#define PUT_B(n) \
#if ((n) == 1) \
STRUCT_INIT \
#elif ((n) 0) \
STRUCT_INIT , PUT_A((n)-1) \
#endif
#define LEN 3
struct mystruct arr[LEN] = \
{PUT_B(LEN)};
Thanks -Albert

Aug 27 '07 #2

P: n/a
an*******@gmail.com writes:
On Aug 27, 1:02 pm, anon.a...@gmail.com wrote:
>In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?

struct mystruct {
int a;
char b;

};

#define STRUCT_INIT {5, 'a'}

#define LEN 3
struct mystruct arr[LEN] = \
{STRUCT_INIT};
<snip>
>
Perhaps it can be done with the preprocessor.
<snip>
#define STRUCT_INIT {5, 'a'}

#define PUT_A(n) \
#if ((n) == 1) \
STRUCT_INIT \
#elif ((n) 0) \
STRUCT_INIT , PUT_B((n)-1) \
#endif
<snip>

You are putting a lot of effort to avoid the simplest for loop. Why?
Just initialise your data in a loop.

--
Ben.
Aug 27 '07 #3

P: n/a
On Aug 27, 1:47 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
<snip>
You are putting a lot of effort to avoid the simplest for loop. Why?
Good question - it made me think!
Here's a scenario: If you have code running at boot time and want to
boot as fast as possible!
Just initialise your data in a loop.
True. -Albert

Aug 27 '07 #4

P: n/a
<an*******@gmail.comwrote in message
news:11**********************@k79g2000hse.googlegr oups.com...
On Aug 27, 1:47 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
<snip>
>You are putting a lot of effort to avoid the simplest for loop. Why?
Good question - it made me think!
Here's a scenario: If you have code running at boot time and want to
boot as fast as possible!
How big is this array anyway? I'd say that if it's less than 1 MB it should
take less than a second. I think that performance should only be considered
when the code is run very frequently and is time-consuming. Not when you're
running it just once and at the initialization phase where users expect the
program to spend some time (a second or two) to initialize.

Abdo Haji-Ali
Programmer
In|Framez
Aug 27 '07 #5

P: n/a
an*******@gmail.com wrote On 08/27/07 09:30,:
On Aug 27, 1:47 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
<snip>
>>You are putting a lot of effort to avoid the simplest for loop. Why?

Good question - it made me think!
Here's a scenario: If you have code running at boot time and want to
boot as fast as possible!
Which do you think is faster: Running a loop that
copies constant data into a million array slots, or
reading a million copies of that data from the boot
device?

--
Er*********@sun.com
Aug 27 '07 #6

P: n/a
On Mon, 27 Aug 2007 11:02:00 +0000, anon.asdf wrote:
Hello!

In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?

struct mystruct {
int a;
char b;
};

#define STRUCT_INIT {5, 'a'}

#define LEN 3
struct mystruct arr[LEN] = \
{STRUCT_INIT};
/* does not work: only 1st element initialized as desired */

/*
I don not want to write
{STRUCT_INIT, STRUCT_INIT, STRUCT_INIT};
since LEN can change!
!!!!!!!!!
*/
<snip>
If you can put this in a separate C file, you could write
a wee program to write that C file, given LEN, and invoke it
as part of your build process.

Off topic: if you use gcc and don't care about portability to other
compilers, you could write
struct mystruct arr[] = { [0 ... LEN-1 ] = STRUCT_INIT};
That's not C but a gcc extension.

Aug 27 '07 #7

P: n/a
On Aug 27, 6:47 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
anon.a...@gmail.com writes:
On Aug 27, 1:02 pm, anon.a...@gmail.com wrote:
In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?
struct mystruct {
int a;
char b;
};
#define STRUCT_INIT {5, 'a'}
#define LEN 3
struct mystruct arr[LEN] = \
{STRUCT_INIT};
<snip>
Perhaps it can be done with the preprocessor.
<snip>
#define STRUCT_INIT {5, 'a'}
#define PUT_A(n) \
#if ((n) == 1) \
STRUCT_INIT \
#elif ((n) 0) \
STRUCT_INIT , PUT_B((n)-1) \
#endif

<snip>

You are putting a lot of effort to avoid the simplest for loop. Why?
Just initialise your data in a loop.
All the world is not a hosted system. And many of us deal with
software that is not loaded from disk, memory that cannot be written
at runtime, and RAM that is scarce and expensive. Of course, in those
situations, you rarely (never?) want all the elements of the array to
contain identical data.

This is one of C's few real shortcomings for writing embedded
software.

The standard way to (or at least, the way I usually) overcome this is
to #define LEN in a header file, and write a simple PC application
that can be invoked by the makefile to generate the initialization
data and save it to a file, so the code becomes

#include "len.h"

struct mystruct arr[LEN] = {
#include "initarr.dat"
};

Regards,

-=Dave

Aug 27 '07 #8

P: n/a
Eric Sosman wrote, On 27/08/07 16:04:
an*******@gmail.com wrote On 08/27/07 09:30,:
>On Aug 27, 1:47 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
<snip>
>>You are putting a lot of effort to avoid the simplest for loop. Why?
Good question - it made me think!
Here's a scenario: If you have code running at boot time and want to
boot as fast as possible!

Which do you think is faster: Running a loop that
copies constant data into a million array slots, or
reading a million copies of that data from the boot
device?
It depends. And there are situations I am aware of which almost
certainly do *not* apply to the OP where the bootup time *is* critical.
--
Flash Gordon
Aug 27 '07 #9

P: n/a
Dave Hansen <id**@hotmail.comwrites:
On Aug 27, 6:47 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
>anon.a...@gmail.com writes:
On Aug 27, 1:02 pm, anon.a...@gmail.com wrote:
In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?
<lost of macro stuff>
>>
You are putting a lot of effort to avoid the simplest for loop. Why?
Just initialise your data in a loop.

All the world is not a hosted system.
Yes, it was a genuine question. I thought it prudent to check, first,
that there *was* reason to go to all the effort of statically
initialising the array.

--
Ben.
Aug 27 '07 #10

P: n/a
an*******@gmail.com writes:
On Aug 27, 1:47 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
<snip>
>You are putting a lot of effort to avoid the simplest for loop. Why?
Good question - it made me think!
That's gratifying -- I fixed the gutters *and* asked a good question.
Today is a Good Day!
Here's a scenario: If you have code running at boot time and want to
boot as fast as possible!
Maybe, maybe, not. It is almost always better to write clear, simple
code first and then make a mess of it if it really is too slow. In
other words the wise programmer will try to ensure that the answer to
a question like this will always be "I used a loop and it was bad
because...".

--
Ben.
Aug 27 '07 #11

P: n/a
On Aug 27, 10:04 am, Eric Sosman <Eric.Sos...@sun.comwrote:
anon.a...@gmail.com wrote On 08/27/07 09:30,:
[...]
Here's a scenario: If you have code running at boot time and want to
boot as fast as possible!

Which do you think is faster: Running a loop that
copies constant data into a million array slots, or
reading a million copies of that data from the boot
device?
Since you asked...

I think reading the data from the boot device is faster than allowing
the startup code to zero the array first (as it must do with
uninitialized static data), then explicitly re-initializing the array
at run time. The larger the array, the more significant the
difference.

Although zeroing the memory is certainly (well, at least _usually_)
much faster than either initialization procedure...

Regards,

-=Dave

Aug 27 '07 #12

P: n/a
Dave Hansen wrote On 08/27/07 17:24,:
On Aug 27, 10:04 am, Eric Sosman <Eric.Sos...@sun.comwrote:
>>anon.a...@gmail.com wrote On 08/27/07 09:30,:

[...]
>>>Here's a scenario: If you have code running at boot time and want to
boot as fast as possible!

Which do you think is faster: Running a loop that
copies constant data into a million array slots, or
reading a million copies of that data from the boot
device?


Since you asked...

I think reading the data from the boot device is faster than allowing
the startup code to zero the array first (as it must do with
uninitialized static data), then explicitly re-initializing the array
at run time. The larger the array, the more significant the
difference.
<topicality level="dwindling">

Seagate calls their Savvio 15K drive the "fastest [...]
in the world," so let's take it as indicative of the higher
range of today's disk speeds. The data sheet gives sustained
transfer rates of between 78 and 112 MB/s, depending on what
part of the platter is used. Assuming that there's no seek
time and no latency (both absorbed by something else we must
read anyhow), the best we can hope for is thus 8.9 ns/byte.

Now to the CPU. Let's assume it runs a loop that stores
eight bytes (the probable size of the O.P.'s struct) per
iteration. To break even with the disk it must complete an
iteration every 71.4 ns. On a 2 GHz machine, that's 142.9
cycles, and since the loop will easily fit in the cache and
since its branch prediction will be almost always right, we
can expect to issue at least one instruction per cycle. So
to beat the disk, all we need is a compiler that translates

for (i = 0; i < LEN; ++i) {
arr[i].a = 5;
arr[i].b = 'a';
}

.... into fewer than 140 instructions per iteration.

YMMV, of course. But on the assumption that people
usually don't lay out big bucks for jackrabbit disks only to
pair them with tortoise-like CPU's (the aforementioned Savvio
goes for $455-655, sez the Web, while $90 gets you an AMD
Athlon at 2.1 GHz), I'd expect to find broadly similar
relations in most systems.

(Of course, the questioner never said he was booting
from a disk, either: All this numerical noodling may be
nothing but nitwittical nonsense.)

</topicality>

--
Er*********@sun.com
Aug 27 '07 #13

P: n/a
<an*******@gmail.comwrote in message
news:11**********************@57g2000hsv.googlegro ups.com...
Hello!

In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?
[...]
Can this be done?
[...]

Yes. You can create meta-lists and expand then using macros. The format is
something like the following most basic example:

#define NULL_NODE
#define YOUR_LIST() ({1, 2}, ({3, 4}, ({5, 6}, NULL_NODE)))
you can expand the list like this:
#define LIST_EXPAND_LVL_3(_node, _next) \
_node

#define LIST_EXPAND_LVL_1(_node, _next) \
_node , LIST_EXPAND_LVL_2 _next

#define LIST_EXPAND_LVL_0(_node, _next) \
_node , LIST_EXPAND_LVL_1 _next

#define LIST_EXPAND_BEGIN(_list) \
LIST_EXPAND_LVL_0 _list
use it like:

LIST_EXPAND_BEGIN(YOUR_LIST())

this will output:

{1, 2} , {3, 4} , {5, 6}
There is a robust example of this in the boost pre-processing library. So,
there is a solution for you with the C preprocessor. Perhaps I will post
some of my older code here that shows off a more complete version of
meta-lists. Its more lightweight than boost stuff. I need to find the code
and clean it off a bit. BTW, would anybody be interested?
Aug 27 '07 #14

P: n/a
"Chris Thomasson" <cr*****@comcast.netwrote in message
news:ZY******************************@comcast.com. ..
<an*******@gmail.comwrote in message
news:11**********************@57g2000hsv.googlegro ups.com...
>Hello!

In the following code-snippet, is it possible to initialize each
element of arr, with STRUCT_INIT?
[...]
>Can this be done?

[...]

Yes. You can create meta-lists and expand then using macros. The format is
something like the following most basic example:
You can also use something like this:

#define CONCAT_X(_t1, _t2)_t1##_t2
#define CONCAT(_t1, _t2)CONCAT_X(_t1, _t2)
#define PLACE_X(_t)_t
#define PLACE_1(_t)PLACE_X(_t)
#define PLACE_2(_t)PLACE_X(_t)PLACE_X(_t)
#define PLACE_3(_t)PLACE_X(_t)PLACE_X(_t)PLACE_X(_t)
#define PLACE_4(_t)PLACE_X(_t)PLACE_X(_t)PLACE_X(_t)PLACE_ X(_t)

/* and on and on to cover the depths you desire */

#define PLACE(_t, _d)CONCAT(PLACE_, _d)(_t)
Then do something like:

#define LEN() 3

typedef struct foo_s {
int i;
char a;
} foo_t;
#define FOO_STATICINIT() { \
PLACE({1, 'x'}, LEN()) \
}
static foo_t g_foo = FOO_STATICINIT();
Would that work for you?

Aug 28 '07 #15

P: n/a
[...]
You can also use something like this:

#define CONCAT_X(_t1, _t2)_t1##_t2
#define CONCAT(_t1, _t2)CONCAT_X(_t1, _t2)
#define PLACE_X(_t)_t
#define PLACE_1(_t)PLACE_X(_t)
#define PLACE_2(_t)PLACE_X(_t)PLACE_X(_t)
#define PLACE_3(_t)PLACE_X(_t)PLACE_X(_t)PLACE_X(_t)
#define PLACE_4(_t)PLACE_X(_t)PLACE_X(_t)PLACE_X(_t)PLACE_ X(_t)

/* and on and on to cover the depths you desire */
[...]

You can amortize the length the PLACE_ macro functions by doing something
like this:

#define PLACE_X(_t)_t
#define PLACE_1(_t)PLACE_X(_t)
#define PLACE_2(_t)PLACE_X(_t)PLACE_X(_t)
#define PLACE_3(_t)PLACE_2(_t)PLACE_X(_t)
#define PLACE_4(_t)PLACE_3(_t)PLACE_X(_t)
#define PLACE_5(_t)PLACE_4(_t)PLACE_X(_t)
#define PLACE_6(_t)PLACE_5(_t)PLACE_X(_t)
#define PLACE_7(_t)PLACE_6(_t)PLACE_X(_t)
#define PLACE_8(_t)PLACE_7(_t)PLACE_X(_t)
#define PLACE_9(_t)PLACE_8(_t)PLACE_X(_t)
#define PLACE_10(_t)PLACE_9(_t)PLACE_X(_t)
#define PLACE_11(_t)PLACE_10(_t)PLACE_X(_t)
#define PLACE_12(_t)PLACE_11(_t)PLACE_X(_t)
#define PLACE_13(_t)PLACE_12(_t)PLACE_X(_t)
#define PLACE_14(_t)PLACE_13(_t)PLACE_X(_t)
#define PLACE_15(_t)PLACE_14(_t)PLACE_X(_t)
#define PLACE_16(_t)PLACE_15(_t)PLACE_X(_t)
#define PLACE_17(_t)PLACE_16(_t)PLACE_X(_t)
#define PLACE_18(_t)PLACE_17(_t)PLACE_X(_t)
#define PLACE_19(_t)PLACE_18(_t)PLACE_X(_t)
#define PLACE_20(_t)PLACE_19(_t)PLACE_X(_t)

/* and on and on to suite your needs... */

:^)

Aug 28 '07 #16

P: n/a
Oops! I made two mistakes:

1: forgot to make g_foo an array!

2: forgot to add commas in the place macros!

So, here is a re-post of the pseudo-code:

#define CONCAT_X(_t1, _t2)_t1##_t2
#define CONCAT(_t1, _t2)CONCAT_X(_t1, _t2)
#define PLACE_X(_t)_t
#define PLACE_1(_t)PLACE_X(_t)
#define PLACE_2(_t)PLACE_X(_t), PLACE_X(_t)
#define PLACE_3(_t)PLACE_2(_t), PLACE_X(_t)
#define PLACE_4(_t)PLACE_3(_t), PLACE_X(_t)
#define PLACE_5(_t)PLACE_4(_t), PLACE_X(_t)
#define PLACE_6(_t)PLACE_5(_t), PLACE_X(_t)
#define PLACE_7(_t)PLACE_6(_t), PLACE_X(_t)
#define PLACE_8(_t)PLACE_7(_t), PLACE_X(_t)
#define PLACE_9(_t)PLACE_8(_t), PLACE_X(_t)
#define PLACE_10(_t)PLACE_9(_t), PLACE_X(_t)
#define PLACE_11(_t)PLACE_10(_t), PLACE_X(_t)
#define PLACE_12(_t)PLACE_11(_t), PLACE_X(_t)
#define PLACE_13(_t)PLACE_12(_t), PLACE_X(_t)
#define PLACE_14(_t)PLACE_13(_t), PLACE_X(_t)
#define PLACE_15(_t)PLACE_14(_t), PLACE_X(_t)
#define PLACE_16(_t)PLACE_15(_t), PLACE_X(_t)
#define PLACE_17(_t)PLACE_16(_t), PLACE_X(_t)
#define PLACE_18(_t)PLACE_17(_t), PLACE_X(_t)
#define PLACE_19(_t)PLACE_18(_t), PLACE_X(_t)
#define PLACE_20(_t)PLACE_19(_t), PLACE_X(_t)
/* and on and on to cover the depths you desire */

#define PLACE(_t, _d)CONCAT(PLACE_, _d)(_t)
Then do something like:

#define LEN() 3

typedef struct foo_s {
int i;
char a;
} foo_t;
#define FOO_STATICINIT() { \
PLACE({1, 'x'}, LEN()) \
}
static foo_t g_foo = FOO_STATICINIT();

Aug 28 '07 #17

P: n/a
[...]

Fu%cking damn! There is an error with the PLACE macros because {1, 'x'} is
going to be treated as two parameters. The trick is to pass the PLACE macro
a name to a macro function that it calls to get at the tokens. I am going to
post some working code in about 10-15 minutes. Please hold...
Aug 28 '07 #18

P: n/a

<an*******@gmail.comwrote in message
news:11**********************@57g2000hsv.googlegro ups.com...
Hello!
[...]
Here is a possible solution in the form of working code:

--------------

#include <stdio.h>
#define CONCAT_X(mp_t1, mp_t2)mp_t1##mp_t2
#define CONCAT(mp_t1, mp_t2)CONCAT_X(mp_t1, mp_t2)
#define PLACE_X(mp_fp)mp_fp()
#define PLACE_1(mp_fp)PLACE_X(mp_fp)
#define PLACE_2(mp_fp)PLACE_X(mp_fp), PLACE_X(mp_fp)
#define PLACE_3(mp_fp)PLACE_2(mp_fp), PLACE_X(mp_fp)
#define PLACE_4(mp_fp)PLACE_3(mp_fp), PLACE_X(mp_fp)
#define PLACE_5(mp_fp)PLACE_4(mp_fp), PLACE_X(mp_fp)
#define PLACE_6(mp_fp)PLACE_5(mp_fp), PLACE_X(mp_fp)
#define PLACE_7(mp_fp)PLACE_6(mp_fp), PLACE_X(mp_fp)
#define PLACE_8(mp_fp)PLACE_7(mp_fp), PLACE_X(mp_fp)
#define PLACE_9(mp_fp)PLACE_8(mp_fp), PLACE_X(mp_fp)
#define PLACE_10(mp_fp)PLACE_9(mp_fp), PLACE_X(mp_fp)
#define PLACE(mp_fp, mp_d)CONCAT(PLACE_, mp_d)(mp_fp)
typedef struct foo_s {
int i;
char a;
} foo_t;
#define FOO_STATICINIT(mp_fp, mp_d) { \
PLACE(mp_fp, mp_d) \
}
#define MYARRAY_DEPTH_1() 4
#define MYARRAY_DEPTH_2() 7
#define MYARRAY_INIT_1() {1, 'x'}
#define MYARRAY_INIT_2() {5, 'a'}
static foo_t g_foo1[MYARRAY_DEPTH_1()] =
FOO_STATICINIT(MYARRAY_INIT_1, MYARRAY_DEPTH_1());
static foo_t g_foo2[MYARRAY_DEPTH_2()] =
FOO_STATICINIT(MYARRAY_INIT_2, MYARRAY_DEPTH_2());
int main(void) {
{
int i;

for(i = 0; i < MYARRAY_DEPTH_1(); ++i) {
printf("g_foo1[%i].i(%i)\ng_foo1[%i].a(%c)\n----\n",
i, g_foo1[i].i, i, g_foo1[i].a);
}

puts("\n\n_____________________________\n\n");

for(i = 0; i < MYARRAY_DEPTH_2(); ++i) {
printf("g_foo2[%i].i(%i)\ng_foo2[%i].a(%c)\n----\n",
i, g_foo2[i].i, i, g_foo2[i].a);
}
}

puts("\n\n\n\
_______________________\npress <enterto exit...\n");
return getchar();
}
-------------
Does that do what you want?

Aug 28 '07 #19

P: n/a
Dave Hansen wrote:
On Aug 27, 10:04 am, Eric Sosman <Eric.Sos...@sun.comwrote:
>anon.a...@gmail.com wrote On 08/27/07 09:30,:
[...]
>>
>>Here's a scenario: If you have code running at boot time and
want to boot as fast as possible!

Which do you think is faster: Running a loop that copies constant
data into a million array slots, or reading a million copies of
that data from the boot device?

Since you asked...

I think reading the data from the boot device is faster than
allowing the startup code to zero the array first (as it must do
with uninitialized static data), then explicitly re-initializing
the array at run time. The larger the array, the more significant
the difference.

Although zeroing the memory is certainly (well, at least _usually_)
much faster than either initialization procedure...
And you get a significantly different answer on systems that use
'copy on write' segments. As usual, that is a system environment
issue, and not germane to c.l.c.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Aug 28 '07 #20

P: n/a
On Aug 28, 3:15 am, "Chris Thomasson" <cris...@comcast.netwrote:
Here is a possible solution in the form of working code:
[snip]
#include <stdio.h>

#define CONCAT_X(mp_t1, mp_t2)mp_t1##mp_t2
#define CONCAT(mp_t1, mp_t2)CONCAT_X(mp_t1, mp_t2)

#define PLACE_X(mp_fp)mp_fp()
#define PLACE_1(mp_fp)PLACE_X(mp_fp)
#define PLACE_2(mp_fp)PLACE_X(mp_fp), PLACE_X(mp_fp)
#define PLACE_3(mp_fp)PLACE_2(mp_fp), PLACE_X(mp_fp)
#define PLACE_4(mp_fp)PLACE_3(mp_fp), PLACE_X(mp_fp)
#define PLACE_5(mp_fp)PLACE_4(mp_fp), PLACE_X(mp_fp)
#define PLACE_6(mp_fp)PLACE_5(mp_fp), PLACE_X(mp_fp)
#define PLACE_7(mp_fp)PLACE_6(mp_fp), PLACE_X(mp_fp)
#define PLACE_8(mp_fp)PLACE_7(mp_fp), PLACE_X(mp_fp)
#define PLACE_9(mp_fp)PLACE_8(mp_fp), PLACE_X(mp_fp)
#define PLACE_10(mp_fp)PLACE_9(mp_fp), PLACE_X(mp_fp)
#define PLACE(mp_fp, mp_d)CONCAT(PLACE_, mp_d)(mp_fp)
It also works with CONCAT_X (directly) on the line above:
#define PLACE(mp_fp, mp_d)CONCAT_X(PLACE_, mp_d)(mp_fp)
>
typedef struct foo_s {
int i;
char a;

} foo_t;

#define FOO_STATICINIT(mp_fp, mp_d) { \
PLACE(mp_fp, mp_d) \

}
^In case someone just copies and gets a compile error - the reason
will be the empty line above }.
>
#define MYARRAY_DEPTH_1() 4
#define MYARRAY_DEPTH_2() 7
#define MYARRAY_INIT_1() {1, 'x'}
#define MYARRAY_INIT_2() {5, 'a'}

static foo_t g_foo1[MYARRAY_DEPTH_1()] =
FOO_STATICINIT(MYARRAY_INIT_1, MYARRAY_DEPTH_1());

static foo_t g_foo2[MYARRAY_DEPTH_2()] =
FOO_STATICINIT(MYARRAY_INIT_2, MYARRAY_DEPTH_2());

int main(void) {
{
int i;

for(i = 0; i < MYARRAY_DEPTH_1(); ++i) {
printf("g_foo1[%i].i(%i)\ng_foo1[%i].a(%c)\n----\n",
i, g_foo1[i].i, i, g_foo1[i].a);
}

puts("\n\n_____________________________\n\n");

for(i = 0; i < MYARRAY_DEPTH_2(); ++i) {
printf("g_foo2[%i].i(%i)\ng_foo2[%i].a(%c)\n----\n",
i, g_foo2[i].i, i, g_foo2[i].a);
}

}

puts("\n\n\n\
_______________________\npress <enterto exit...\n");
return getchar();

}
[snip]
Does that do what you want?
Yes, unbelievable!
Thanks for that! I'm trying to figure out how it does what it does!

Things like removing "()" from a macro, and passing it along
#define MYARRAY_INIT_1() {1, 'x'}
...
static foo_t g_foo1[MYARRAY_DEPTH_1()] =
FOO_STATICINIT(MYARRAY_INIT_1, MYARRAY_DEPTH_1());
and then putting it back at the end, are sneaky! :)
#define PLACE_X(mp_fp)mp_fp()
And I've got an idea what it's for, but I cannot deduce the
"semantics"...
I'll probably have to read up on the preprocessor to fully understand
it.

-Albert

Aug 28 '07 #21

P: n/a
On Aug 28, 3:15 am, "Chris Thomasson" <cris...@comcast.netwrote:
#include <stdio.h>

#define CONCAT_X(mp_t1, mp_t2)mp_t1##mp_t2
#define CONCAT(mp_t1, mp_t2)CONCAT_X(mp_t1, mp_t2)

#define PLACE_X(mp_fp)mp_fp()
#define PLACE_1(mp_fp)PLACE_X(mp_fp)
#define PLACE_2(mp_fp)PLACE_X(mp_fp), PLACE_X(mp_fp)
#define PLACE_3(mp_fp)PLACE_2(mp_fp), PLACE_X(mp_fp)
#define PLACE_4(mp_fp)PLACE_3(mp_fp), PLACE_X(mp_fp)
#define PLACE_5(mp_fp)PLACE_4(mp_fp), PLACE_X(mp_fp)
#define PLACE_6(mp_fp)PLACE_5(mp_fp), PLACE_X(mp_fp)
#define PLACE_7(mp_fp)PLACE_6(mp_fp), PLACE_X(mp_fp)
#define PLACE_8(mp_fp)PLACE_7(mp_fp), PLACE_X(mp_fp)
#define PLACE_9(mp_fp)PLACE_8(mp_fp), PLACE_X(mp_fp)
#define PLACE_10(mp_fp)PLACE_9(mp_fp), PLACE_X(mp_fp)
#define PLACE(mp_fp, mp_d)CONCAT(PLACE_, mp_d)(mp_fp)
It also works with CONCAT_X above, i.e.
#define PLACE(mp_fp, mp_d)CONCAT_X(PLACE_, mp_d)(mp_fp)

typedef struct foo_s {
int i;
char a;

} foo_t;

#define FOO_STATICINIT(mp_fp, mp_d) { \
PLACE(mp_fp, mp_d) \

}
In case someone is just copy-pasting: to prevent a compile-error, the
empty line above "}" should be removed
>
#define MYARRAY_DEPTH_1() 4
#define MYARRAY_DEPTH_2() 7
#define MYARRAY_INIT_1() {1, 'x'}
#define MYARRAY_INIT_2() {5, 'a'}

static foo_t g_foo1[MYARRAY_DEPTH_1()] =
FOO_STATICINIT(MYARRAY_INIT_1, MYARRAY_DEPTH_1());

static foo_t g_foo2[MYARRAY_DEPTH_2()] =
FOO_STATICINIT(MYARRAY_INIT_2, MYARRAY_DEPTH_2());

int main(void) {
{
int i;

for(i = 0; i < MYARRAY_DEPTH_1(); ++i) {
printf("g_foo1[%i].i(%i)\ng_foo1[%i].a(%c)\n----\n",
i, g_foo1[i].i, i, g_foo1[i].a);
}

puts("\n\n_____________________________\n\n");

for(i = 0; i < MYARRAY_DEPTH_2(); ++i) {
printf("g_foo2[%i].i(%i)\ng_foo2[%i].a(%c)\n----\n",
i, g_foo2[i].i, i, g_foo2[i].a);
}

}

puts("\n\n\n\
_______________________\npress <enterto exit...\n");
return getchar();

}

-------------

Does that do what you want?
Yes! Unbelievable!
Thanks for that!

I'm trying to understand it:

..
..

Things like removing ()
#define MYARRAY_INIT_1() {1, 'x'}
...
static foo_t g_foo1[MYARRAY_DEPTH_1()] =
FOO_STATICINIT(MYARRAY_INIT_1, MYARRAY_DEPTH_1());
and then including them at the end are sneaky! :)
#define PLACE_X(mp_fp)mp_fp()
..
..
I believe I know why this is done (prevent premature expansion), but I
think I really need to read some more about the C preprocessor to
understand the exact "semantics".

Thanks -Albert

Aug 28 '07 #22

P: n/a
"Chris Thomasson" <cr*****@comcast.netwrote in message
news:fO******************************@comcast.com. ..
>
<an*******@gmail.comwrote in message
news:11**********************@57g2000hsv.googlegro ups.com...
[...]
#define PLACE_X(mp_fp)mp_fp()
#define PLACE_1(mp_fp)PLACE_X(mp_fp)
#define PLACE_2(mp_fp)PLACE_X(mp_fp), PLACE_X(mp_fp)
#define PLACE_3(mp_fp)PLACE_2(mp_fp), PLACE_X(mp_fp)
#define PLACE_4(mp_fp)PLACE_3(mp_fp), PLACE_X(mp_fp)
#define PLACE_5(mp_fp)PLACE_4(mp_fp), PLACE_X(mp_fp)
#define PLACE_6(mp_fp)PLACE_5(mp_fp), PLACE_X(mp_fp)
#define PLACE_7(mp_fp)PLACE_6(mp_fp), PLACE_X(mp_fp)
#define PLACE_8(mp_fp)PLACE_7(mp_fp), PLACE_X(mp_fp)
#define PLACE_9(mp_fp)PLACE_8(mp_fp), PLACE_X(mp_fp)
#define PLACE_10(mp_fp)PLACE_9(mp_fp), PLACE_X(mp_fp)
#define PLACE(mp_fp, mp_d)CONCAT(PLACE_, mp_d)(mp_fp)
[...]

You can conditionally specialize the PLACE_ macro function table for
specific sizes. For instance, lets say you need to work with arrays larger
than [10], perhaps you need 50:

--------------
#if ! defined(PLACE_50)
#define PLACE_50(mp_fp) \
PLACE_10(mp_fp), PLACE_10(mp_fp), PLACE_10(mp_fp), \
PLACE_10(mp_fp), PLACE_10(mp_fp)
#endif
--------------

Now you can do something like:

--------------
typedef struct foo_s {
char a;
char b;
char c;
} foo_t;

#define INIT() {'a', 'b', 'c'}

static foo_t g_foo[50] = {PLACE(INIT, 50)}

[...]
--------------

So, it can be "extended" to some fairly large array sizes...

Also, if you really want to get tricky... You could paramertize the
"delayed" macro call, (e.g., mp_fp parameter) with some state. For instance,
you could pass it an index:
--------------
#define PLACE_X(mp_fp, mp_idx)mp_fp(mp_idx)
#define PLACE_1(mp_fp)PLACE_X(mp_fp, 0)
#define PLACE_2(mp_fp)PLACE_1(mp_fp), PLACE_X(mp_fp, 1)
#define PLACE_3(mp_fp)PLACE_2(mp_fp), PLACE_X(mp_fp, 2)
#define PLACE_4(mp_fp)PLACE_3(mp_fp), PLACE_X(mp_fp, 3)
#define PLACE_5(mp_fp)PLACE_4(mp_fp), PLACE_X(mp_fp, 4)
#define PLACE_6(mp_fp)PLACE_5(mp_fp), PLACE_X(mp_fp, 5)
#define PLACE_7(mp_fp)PLACE_6(mp_fp), PLACE_X(mp_fp, 6)
#define PLACE_8(mp_fp)PLACE_7(mp_fp), PLACE_X(mp_fp, 7)
#define PLACE_9(mp_fp)PLACE_8(mp_fp), PLACE_X(mp_fp, 8)
#define PLACE_10(mp_fp)PLACE_9(mp_fp), PLACE_X(mp_fp, 9)
#define PLACE(mp_fp, mp_d)CONCAT(PLACE_, mp_d)(mp_fp)
--------------

Now you can do something cool like:

--------------

static char const g_data_0[] = "Data0";
static char const g_data_1[] = "Data2";
static char const g_data_2[] = "Data3";

typedef struct foo_s {
size_t id;
char const* const data;
} foo_t;

#define INIT(mp_idx) { (mp_idx), CONCAT(g_data_, mp_idx) }

static foo_t g_foo[8] = {PLACE(INIT, 3)}

[...]
--------------


There is a lot of crazy shi% you can do with the c pre-processor..

:^0


You could paramertize the "delayed" macro call even further! For instance,
you could pass it a token:
--------------
#define PLACE_X(mp_fp, mp_idx, mp_t)mp_fp(mp_idx, mp_t))
#define PLACE_1(mp_fp, mp_t)PLACE_X(mp_fp, 0, mp_t)
#define PLACE_2(mp_fp, mp_t)PLACE_1(mp_fp, mp_t), PLACE_X(mp_fp, 1, mp_t)
#define PLACE_3(mp_fp, mp_t)PLACE_2(mp_fp, mp_t), PLACE_X(mp_fp, 2, mp_t)
#define PLACE_4(mp_fp, mp_t)PLACE_3(mp_fp, mp_t), PLACE_X(mp_fp, 3, mp_t)
#define PLACE_5(mp_fp, mp_t)PLACE_4(mp_fp, mp_t), PLACE_X(mp_fp, 4, mp_t)
#define PLACE_6(mp_fp, mp_t)PLACE_5(mp_fp, mp_t), PLACE_X(mp_fp, 5, mp_t)
#define PLACE_7(mp_fp, mp_t)PLACE_6(mp_fp, mp_t), PLACE_X(mp_fp, 6, mp_t)
#define PLACE_8(mp_fp, mp_t)PLACE_7(mp_fp, mp_t), PLACE_X(mp_fp, 7, mp_t)
#define PLACE_9(mp_fp, mp_t)PLACE_8(mp_fp, mp_t), PLACE_X(mp_fp, 8, mp_t)
#define PLACE_10(mp_fp, mp_t)PLACE_9(mp_fp, mp_t), PLACE_X(mp_fp, 9, mp_t)
#define PLACE(mp_fp, mp_t, mp_d)CONCAT(PLACE_, mp_d)(mp_fp, mp_t)
--------------


Now you can do something cool like:

--------------

static char const g_data_0[] = "Data0";
static char const g_data_1[] = "Data2";
static char const g_data_2[] = "Data3";

typedef struct foo_s {
size_t id;
char const* const data;
} foo_t;

#define INIT(mp_idx, mp_t) { (mp_idx), CONCAT(mp_t, mp_idx) }

static foo_t g_foo[8] = {PLACE(INIT, g_data_, 3)}

[...]
--------------

:^)
Aug 28 '07 #23

P: n/a
[...]
>
Now you can do something cool like:

--------------

static char const g_data_0[] = "Data0";
static char const g_data_1[] = "Data2";
static char const g_data_2[] = "Data3";

typedef struct foo_s {
size_t id;
char const* const data;
} foo_t;

#define INIT(mp_idx) { (mp_idx), CONCAT(g_data_, mp_idx) }

static foo_t g_foo[8] = {PLACE(INIT, 3)}
^^^^^^^^^^^^^^^
that should of course be:

static foo_t g_foo[3] = {PLACE(INIT, 3)};

[...]

>

Now you can do something cool like:

--------------

static char const g_data_0[] = "Data0";
static char const g_data_1[] = "Data2";
static char const g_data_2[] = "Data3";

typedef struct foo_s {
size_t id;
char const* const data;
} foo_t;

#define INIT(mp_idx, mp_t) { (mp_idx), CONCAT(mp_t, mp_idx) }

static foo_t g_foo[8] = {PLACE(INIT, g_data_, 3)}
^^^^^^^^^^^^^^^^^^^

ditto:

static foo_t g_foo[3] = {PLACE(INIT, 3)};

Sorry about that.
Aug 28 '07 #24

This discussion thread is closed

Replies have been disabled for this discussion.