DSPRelated.com
Forums

Macro expansion order

Started by Kenneth Porter July 9, 2003
I'm not sure if this is a flaw in the compiler or if I'm violating the
standard. Compile the following with version 6.2.3, "cc21k -c -21065L foo.c":

#define MAC(a,b,c) { a,b,c }
#define MULTPARM 1,2
struct X { int a, b, c; } x = MAC(MULTPARM, 3);

The result is:

"foo4.c", line 3: cc0054-D: error: too few arguments in macro invocation
struct X { int a, b, c; } x = MAC(MULTPARM, 3);

It looks like there's a sensitivity to the order of macro expansion, and I'm
not sure if this is defined by the standard.

In my actual application, for different target architectures, the structure
has a different number of components (there's an extra for SHARC's), the MAC
macro has a different number of parameters, hence the MULTPARM macro has a
different number of values.

For now I'm wrapping the whole structure initialization in an #ifdef, but I'd
like to do something like this if it's legal:

#ifdef __ADSP21065L__
#define MULTPARM 1,2
#else
#define MULTPARM 1
#endif



On Wed, 9 Jul 2003, Kenneth Porter wrote:

> I'm not sure if this is a flaw in the compiler or if I'm violating the
> standard. Compile the following with version 6.2.3, "cc21k -c -21065L foo.c":
>
> #define MAC(a,b,c) { a,b,c }
> #define MULTPARM 1,2
> struct X { int a, b, c; } x = MAC(MULTPARM, 3);
>
> The result is:
>
> "foo4.c", line 3: cc0054-D: error: too few arguments in macro invocation
> struct X { int a, b, c; } x = MAC(MULTPARM, 3);
>
> It looks like there's a sensitivity to the order of macro expansion, and I'm
> not sure if this is defined by the standard.

It's working from the outside in. I'm not familiar with the ccp macro
expansion method, but it may be a multiple pass operation which works
on one level at a time and just keeps going till there are no more
levels to do. Some won't let you go more than 8 levels.

You can have 2 macros that are similar and get around this:

#define MULTPART 1,2
#define MAC(a, b, c) {a, b, c}
#define MACm( c) { MULTPART, c}

So places where you have 3 arguments you include all 3, and
places where you need expansion you have only 1.

> In my actual application, for different target architectures, the structure
> has a different number of components (there's an extra for SHARC's), the MAC
> macro has a different number of parameters, hence the MULTPARM macro has a
> different number of values.

then ifdef does seem to be a good solution.

> For now I'm wrapping the whole structure initialization in an #ifdef, but I'd
> like to do something like this if it's legal:
>
> #ifdef __ADSP21065L__
> #define MULTPARM 1,2
> #else
> #define MULTPARM 1
> #endif

But then you should define MAC as MACm above, and it'll
work in both cases automaticly.

Patience, persistence, truth,
Dr. mike



Here's the reply from ADI, quoting the relevant part of the standard.

------------ Forwarded Message ------------
Subject: PR18068

A solution would be to use the macro MULTPARM in the MAC macro as shown
below.
#ifdef __ADSP21065L__
# define MULTPARM 1,2
#else
# define MULTPARM 1
#endif

#define MAC(c) { MULTPARM, c }

#ifdef __ADSP21065L__
struct X { int a, b, c; } x = MAC(3);
#else
struct X { int a, b; } x = MAC(3);
#endif

This should produce the expected result
cc21k example.c -E
..
struct X { int a, b; } x = { 1, 3 };

cc21k example -E -21065L
..
struct X { int a, b, c; } x = { 1,2, 3 };

The ANSI ISO IEC 14882 1998 Macro Replacement section 16.3 (page 305)
paragraph 10 states:
"The sequence of preprocessing tokens bounded by the out-side most
matching parentheses forms the list of arguments for the
function-like macro. The individual arguments within the list are
separated by comma preprocessing
tokens, but comma preprocessing tokens between matching inner
parentheses do not separate arguments. If (before argument
substitution) any argument consists of no preprocessing tokens, the
behaviour is undefined. If there
are sequences of preprocessing tokens within the list of arguments
that would otherwise act as preprocessing directives, the behaviour is
undefined."

The reply received from Dr Mike Rosing also looks like a good solution.

---------- End Forwarded Message ----------



On Thu, 10 Jul 2003, Kenneth Porter wrote:

> If there
> are sequences of preprocessing tokens within the list of arguments
> that would otherwise act as preprocessing directives, the behaviour is
> undefined."

That's the problem. So you have to make it obvious.

> The reply received from Dr Mike Rosing also looks like a good solution.

I like your #if sequence too. You might have to define the processor
yourself, but at least all the code will be transportable.

Thanks for posting ADI's response.

Patience, persistence, truth,
Dr. mike



--On Thursday, July 10, 2003 6:38 AM -0700 Mike Rosing <>
wrote:

> I like your #if sequence too. You might have to define the processor
> yourself, but at least all the code will be transportable.

Initially I coded something like:

X x = MAC(xxx,
#if defined(__ADSP21065L__)
yyy,zzz,
#else
aaa,
#endif
bbb,ccc);

The ADI compiler is fine with this, but the ancient Borland compiler I use for
the 80186 version of my code choked. Hence I had to tinker around to come up
with something that made both environments happy.

I've got it ported to Blackfin as well, but it's more like the 80186 so that
wasn't so much of a stretch. The biggest issue porting 80186 code to SHARC was
the 32-bit char, and the assumption that casting to short or char caused
masking to 16 or 8 bits. I grepped my code for such casts and switched those
to a macro call (MASK_TO_8_BITS(x)) to make the intent clear.

If anyone here is contemplating Blackfin as a target, be aware that VDSP lacks
64 bit doubles for that beast. I had a spot where I needed a 48-bit temporary
and we had to code our own extended precision in assembly for it.