How do I wind this into a nested loop?

R

Robbie Hatley

Greetings, group. I've got a big MESS of code in one of the source
files of my employer's primary software product. It's basically
assignments of automatically-generated control-id macros to arrays,
so they can be easily accessed by nested for loops. This mess
looks like:

AuxChanId [0] [0] = IG1_CH1;
AuxTypeId [0] [0] = IG1_TYPE1;
AuxOperId [0] [0] = IG1_OP1;
AuxThreId [0] [0] = IG1_THRESH1;
AuxMinuId [0] [0] = IG1_MM1;
AuxSecoId [0] [0] = IG1_SS1;
AuxHoldId [0] [0] = IG1_HOLD1;
AuxChanId [0] [1] = IG1_CH2;
AuxTypeId [0] [1] = IG1_TYPE2;
AuxOperId [0] [1] = IG1_OP2;
AuxThreId [0] [1] = IG1_THRESH2;
AuxMinuId [0] [1] = IG1_MM2;
AuxSecoId [0] [1] = IG1_SS2;
AuxHoldId [0] [1] = IG1_HOLD2;
AuxChanId [0] [2] = IG1_CH3;
AuxTypeId [0] [2] = IG1_TYPE3;
AuxOperId [0] [2] = IG1_OP3;
AuxThreId [0] [2] = IG1_THRESH3;
AuxMinuId [0] [2] = IG1_MM3;
AuxSecoId [0] [2] = IG1_SS3;
AuxHoldId [0] [2] = IG1_HOLD3;
.
.
.
AuxChanId [1] [0] = IG2_CH1;
AuxTypeId [1] [0] = IG2_TYPE1;
AuxOperId [1] [0] = IG2_OP1;
AuxThreId [1] [0] = IG2_THRESH1;
AuxMinuId [1] [0] = IG2_MM1;
AuxSecoId [1] [0] = IG2_SS1;
AuxHoldId [1] [0] = IG2_HOLD1;
.
.
.
(continuing likewise for hundreds more lines)
.
.
.

Ugly as hell and takes up a lot of space. Is this any way to wind this
into nested for loops, perhaps by using preprocessor commands to
generate the macro name strings and insert them on the right?
Perhaps something using the stringizing and concatenation commands?
I don't see how to go about it, though... or even if it CAN be done.
 
W

William Pursell

On Feb 29, 10:29 pm, "Robbie Hatley"
Greetings, group. I've got a big MESS of code in one of the source
files of my employer's primary software product. It's basically
assignments of automatically-generated control-id macros to arrays,
so they can be easily accessed by nested for loops. This mess
looks like:

AuxChanId [0] [0] = IG1_CH1;
AuxTypeId [0] [0] = IG1_TYPE1;

Personally, I would use some other language to generate
the code. But, you could try something like the
following, which will work to generate code for
a 2x2 array for AuxTypeI. It should be straightforward
to expand it to larger arrays. (Once again, it's
a good thing the trailing comma is allowed in
initializers!):

#define _TYPE(x) { IG##x##_TYPE1, IG##x##_TYPE2 },
#define TYPE _TYPE(1) _TYPE(2)

int AuxTypeId [][2] = { TYPE };
 
B

burton.samogradNOSP

Robbie Hatley said:
Greetings, group. I've got a big MESS of code in one of the source
files of my employer's primary software product. It's basically
assignments of automatically-generated control-id macros to arrays,
so they can be easily accessed by nested for loops. This mess
looks like:

AuxChanId [0] [0] = IG1_CH1;
AuxTypeId [0] [0] = IG1_TYPE1;
.
.
(continuing likewise for hundreds more lines)
.
Ugly as hell and takes up a lot of space. Is this any way to wind this
into nested for loops, perhaps by using preprocessor commands to
generate the macro name strings and insert them on the right?
Perhaps something using the stringizing and concatenation commands?
I don't see how to go about it, though... or even if it CAN be done.

Personally, I would generate it with a shell (sh) script and then
either include the generated source or compile it to a seperate object
file and then link it in.

Or, the C preprocessor macros (as suggested by another) could clean it
up quite a bit.

But then again, if it ain't broke...
 
P

Peter Nilsson

William Pursell said:
...
Personally, I would use some other language to generate
the code.  But, you could try something like the
following, which will work to generate code for
a 2x2 array for AuxTypeI.  It should be straightforward
to expand it to larger arrays.  (Once again, it's
a good thing the trailing comma is allowed in
initializers!):

#define _TYPE(x) { IG##x##_TYPE1, IG##x##_TYPE2 },

With the exception of predefined macros, identifiers
with a leading underscore followed by an upper case
letter are reserved for any use.

This goes for _TYPE1 and _TYPE2 as well as _TYPE.
#define TYPE _TYPE(1) _TYPE(2)

int AuxTypeId [][2] = { TYPE };

A more detailed sample is...

enum { /* some dummy values for testing */
IG1_CH1, IG1_TYPE1,
IG1_CH2, IG1_TYPE2,
IG1_CH3, IG1_TYPE3,
IG2_CH1, IG2_TYPE1,
IG2_CH2, IG2_TYPE2,
IG2_CH3, IG2_TYPE3,
IG3_CH1,
IG3_CH2,
IG3_CH3
};

#define ARRAY(T,R,C) ROWS_ ## R (T,C)

#define ROWS_1(T,C) ROW(T,C,1)
#define ROWS_2(T,C) ROW(T,C,1), ROW(T,C,2)
#define ROWS_3(T,C) ROW(T,C,1), ROW(T,C,2), ROW(T,C,3)
/* : */

#define ROW(T,C,r) { COL_ ## C (T,r) }

#define COL_1(T,r) ITEM(T,r,1)
#define COL_2(T,r) ITEM(T,r,1), ITEM(T,r,2)
#define COL_3(T,r) ITEM(T,r,1), ITEM(T,r,2), ITEM(T,r,3)
/* : */

#define ITEM(T,r,c) IG ## r ## _ ## T ## c

int AuxChanID[3][3] = { ARRAY(CH, 3, 3) };
int AuxTypeID[2][3] = { ARRAY(TYPE, 2, 3) };
 
R

Robbie Hatley

William said:
On Feb 29, 10:29 pm, "Robbie Hatley"
Greetings, group. I've got a big MESS of code in one of the source
files of my employer's primary software product. It's basically
assignments of automatically-generated control-id macros to arrays,
so they can be easily accessed by nested for loops. This mess
looks like:

AuxChanId [0] [0] = IG1_CH1;
AuxTypeId [0] [0] = IG1_TYPE1;

Personally, I would use some other language to generate
the code. But, you could try something like the
following, which will work to generate code for
a 2x2 array for AuxTypeI. It should be straightforward
to expand it to larger arrays. (Once again, it's
a good thing the trailing comma is allowed in
initializers!):

#define _TYPE(x) { IG##x##_TYPE1, IG##x##_TYPE2 },
#define TYPE _TYPE(1) _TYPE(2)

int AuxTypeId [][2] = { TYPE };

Wow, that's cool! So it *can* be done. I've got 7 4x8 arrays, so let
me see if I can take that ball and run with it....

#define CH_ROW(x) \
{ IG##x##_CH1, IG##x##_CH2, IG##x##_CH3, IG##x##_CH4, \
IG##x##_CH5, IG##x##_CH6, IG##x##_CH7, IG##x##_CH8, },

#define CH_INIT { CH_ROW(1) CH_ROW(2) CH_ROW(3) CH_ROW(4) }

( ... and the same kind of thing for the other 6 arrays ... )

So now, my definition/initialization for my arrays looks like:

int AuxChanId [4] [8] = CH_INIT;
int AuxTypeId [4] [8] = TYPE_INIT;
int AuxOperId [4] [8] = OP_INIT;
int AuxThreId [4] [8] = THRESH_INIT;
int AuxMinuId [4] [8] = MM_INIT;
int AuxSecoId [4] [8] = SS_INIT;
int AuxHoldId [4] [8] = HOLD_INIT;

Perhaps a little complicated, but I think it still beats my old way,
which was to assign all 224 elements individually:

AuxChanId [0] [0] = IG1_CH1;
AuxTypeId [0] [0] = IG1_TYPE1;
AuxOperId [0] [0] = IG1_OP1;
AuxThreId [0] [0] = IG1_THRESH1;
AuxMinuId [0] [0] = IG1_MM1;
AuxSecoId [0] [0] = IG1_SS1;
AuxHoldId [0] [0] = IG1_HOLD1;
... etc ...
AuxChanId [3] [7] = IG4_CH8;
AuxTypeId [3] [7] = IG4_TYPE8;
AuxOperId [3] [7] = IG4_OP8;
AuxThreId [3] [7] = IG4_THRESH8;
AuxMinuId [3] [7] = IG4_MM8;
AuxSecoId [3] [7] = IG4_SS8;
AuxHoldId [3] [7] = IG4_HOLD8;
// 224 lines of code, total

The C preprocessor is truly an amazing machine.

Thanks for the tips!
 
R

Robbie Hatley

Peter Nilsson wrote:

========BEGIN QUOTE=======================
A more detailed sample is...

enum { /* some dummy values for testing */
IG1_CH1, IG1_TYPE1,
IG1_CH2, IG1_TYPE2,
IG1_CH3, IG1_TYPE3,
IG2_CH1, IG2_TYPE1,
IG2_CH2, IG2_TYPE2,
IG2_CH3, IG2_TYPE3,
IG3_CH1,
IG3_CH2,
IG3_CH3
};

#define ARRAY(T,R,C) ROWS_ ## R (T,C)

#define ROWS_1(T,C) ROW(T,C,1)
#define ROWS_2(T,C) ROW(T,C,1), ROW(T,C,2)
#define ROWS_3(T,C) ROW(T,C,1), ROW(T,C,2), ROW(T,C,3)
/* : */

#define ROW(T,C,r) { COL_ ## C (T,r) }

#define COL_1(T,r) ITEM(T,r,1)
#define COL_2(T,r) ITEM(T,r,1), ITEM(T,r,2)
#define COL_3(T,r) ITEM(T,r,1), ITEM(T,r,2), ITEM(T,r,3)
/* : */

#define ITEM(T,r,c) IG ## r ## _ ## T ## c

int AuxChanID[3][3] = { ARRAY(CH, 3, 3) };
int AuxTypeID[2][3] = { ARRAY(TYPE, 2, 3) };

===========END QUOTE=====================================

(For some reason, my mail prog refuses to prefix lines of
that message with "> " for quoting in reply. Weird.)

I didn't even realize that function-like macros could have
multiple arguments! Fascinating! I used just 1 argument,
so what I came up with (based on Peter Nilsson's technique),
was this:

#define CH_ROW(x) \
{ IG##x##_CH1, IG##x##_CH2, IG##x##_CH3, IG##x##_CH4, \
IG##x##_CH5, IG##x##_CH6, IG##x##_CH7, IG##x##_CH8, },

#define CH_INIT { CH_ROW(1) CH_ROW(2) CH_ROW(3) CH_ROW(4) }

#define TYPE_ROW(x) \
{ IG##x##_TYPE1, IG##x##_TYPE2, IG##x##_TYPE3, IG##x##_TYPE4, \
IG##x##_TYPE5, IG##x##_TYPE6, IG##x##_TYPE7, IG##x##_TYPE8, },

#define TYPE_INIT { TYPE_ROW(1) TYPE_ROW(2) TYPE_ROW(3) TYPE_ROW(4) }

(... and likewise for the other 5 arrays as well ...)

Certainly that could be simplified a lot by using multiple arguments.
And that would reduce the likelyhood of errors, as well.
I'll get to work on that. Thanks for the tips!

By the way, are you sure it's legal to #define ARRAY, then ROW,
then ITEM, in that order? Isn't that going to cause "undefined
identifier" errors? Or does the preprocessor handle that by
doing multiple passes?
 
R

Robbie Hatley

I'd written:
... so what I came up with (based on Peter Nilsson's technique),
was this: ...

Oops, that should have been "William Pursell", not "Peter Nilsson".
Hate to self-nit-pick, but gotta give credit to *BOTH* gentlemen
for their asistance on this matter.

I finally got my 224 lines of messy code boiled down to this:

#define AUXI_ITEM(t,r,c) IG ## r ## _ ## t ## c

#define AUXI_ROW(t,r) \
{ AUXI_ITEM(t,r,1), AUXI_ITEM(t,r,2), AUXI_ITEM(t,r,3), AUXI_ITEM(t,r,4), \
AUXI_ITEM(t,r,5), AUXI_ITEM(t,r,6), AUXI_ITEM(t,r,7), AUXI_ITEM(t,r,8) }

#define AUXI_ARRAY(t) \
{AUXI_ROW(t,1), AUXI_ROW(t,2), AUXI_ROW(t,3), AUXI_ROW(t,4)}

EXTERN int AuxChanId [4] [8] INIT_TO(AUXI_ARRAY(CH) );
EXTERN int AuxTypeId [4] [8] INIT_TO(AUXI_ARRAY(TYPE) );
EXTERN int AuxOperId [4] [8] INIT_TO(AUXI_ARRAY(OP) );
EXTERN int AuxThreId [4] [8] INIT_TO(AUXI_ARRAY(THRESH) );
EXTERN int AuxMinuId [4] [8] INIT_TO(AUXI_ARRAY(MM) );
EXTERN int AuxSecoId [4] [8] INIT_TO(AUXI_ARRAY(SS) );
EXTERN int AuxHoldId [4] [8] INIT_TO(AUXI_ARRAY(HOLD) );

*MUCH* better! Thanks to Willam Pursell and Peter Nilsson for all their
help!
 
W

William Pursell

With the exception of predefined macros, identifiers
with a leading underscore followed by an upper case
letter are reserved for any use.


Thank you for the reminder. For some reason, I
know this fact and apply it carefully to 'real'
symbols, but continue to misapply it to
pre-processor names. Apparently, I will need
to be burned by it in real life before I
finally learn.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top