Why can't a defined symbol be part of a typedef?

A

aekalman

Hi all.

I'm revising part of a large body of code that runs on a variety of
very different targets, and one of the things I'd like to do is move
away from certain "#define'd types" in favor of typedefs. This, mainly
because occasionally a user forgets that these are pointer "types",
and declares one or more variable on the same line, leading to errors.

E.g. right now I have this, which works fine, with the caveat that
only a single variable should be declared per line (because it's a
pointer variable):

typedef struct ecb OStypeEcb;
#define OStypeEcbP OStypeEcb OSLOC_ECB *

used thusly:

OStypeEcbP myEcbP;

and not

OStypeEcbP myEcbP, yourEcbP; // bad!

What is OSLOC_ECB, you ask? Well, it's a bank qualifier for certain
targets (e.g. Microchip PIC16's, where OSLOC_ECB might be nothing,
bank1, bank2 or bank3). The user can

#define OSLOC_ECB

or

#define OSLOC_ECB bank1

etc. to indicate where the objects (the ecb's) being pointed to are
located. So far, so good.

Naturally, I would prefer to have this:

typedef struct ecb OStypeEcb;
typedef OStypeEcb OSLOC_ECB * OStypeEcbP;

But it fails to compile, and I don't really understand why. OSLOC_ECB
is defined long before the typedef is processed by the compiler, yet
preprocessor output (CodeWarrior, in this case) of that line (for
OSLOC_ECB defined to be blank/nothing) reveals

typedef OStypeEcb OSLOC_ECB * OStypeEcbP;

instead of

typedef OStypeEcb * OStypeEcbP;

which is what I would have expected.

Can someone explain to me why defined symbols are not converted inside
the typedef, and if there's a way around this?

Thanks,

--Andrew
aek at pumpkininc dot com
 
A

Arthur J. O'Dwyer

#define OSLOC_ECB
typedef struct ecb OStypeEcb;
typedef OStypeEcb OSLOC_ECB * OStypeEcbP;

But it fails to compile, and I don't really understand why. OSLOC_ECB
is defined long before the typedef is processed by the compiler, yet
preprocessor output (CodeWarrior, in this case) of that line (for
OSLOC_ECB defined to be blank/nothing) reveals

typedef OStypeEcb OSLOC_ECB * OStypeEcbP;

Try this sample program in CodeWarrior. The code you're
describing is perfectly correct, so if it really is as you
describe, then CodeWarrior must have a bug. But that seems
unlikely to me...

#define FOO

typedef int FOO *bar;

int main()
{
bar baz;
baz = (int*)0;
}

If that code doesn't compile, then your compiler is broken.
On the other hand, are you absolutely *sure* you didn't have
the equivalent of

typedef int FOO *bar;

#define FOO

int main()
{
bar baz;
baz = (int*)0;
}

in your real code? Because that /isn't/ valid C, even though

#define bar int FOO *
#define FOO

is.

HTH,
-Arthur
 
E

Eric Sosman

aekalman said:
Hi all.

I'm revising part of a large body of code that runs on a variety of
very different targets, and one of the things I'd like to do is move
away from certain "#define'd types" in favor of typedefs. This, mainly
because occasionally a user forgets that these are pointer "types",
and declares one or more variable on the same line, leading to errors.

E.g. right now I have this, which works fine, with the caveat that
only a single variable should be declared per line (because it's a
pointer variable):

typedef struct ecb OStypeEcb;
#define OStypeEcbP OStypeEcb OSLOC_ECB *

used thusly:

OStypeEcbP myEcbP;

and not

OStypeEcbP myEcbP, yourEcbP; // bad!

What is OSLOC_ECB, you ask? Well, it's a bank qualifier for certain
targets (e.g. Microchip PIC16's, where OSLOC_ECB might be nothing,
bank1, bank2 or bank3). The user can

#define OSLOC_ECB

or

#define OSLOC_ECB bank1

etc. to indicate where the objects (the ecb's) being pointed to are
located. So far, so good. [...]

Not as far as I can see. With the latter definition
of OSLOC_ECB your sample usage goes

OStypeEcbP myEcbP;
-> OStypeEcb OSLOC_ECB * myEcbP;
-> OStypeEcb bank1 * myEcbP;

.... which looks like nonsense, unless `bank1' is itself
#define'd to something, or unless it's a special beyond-
the-C-language extension recognized by the compiler at
hand. If there's another #define lurking somewhere you
haven't shown it (or I've overlooked it). If `bank1' is
a non-C extension keyword, then you need to address your
question to the non-C compiler.
 
A

aekalman

Arthur J. O'Dwyer said:
If that code doesn't compile, then your compiler is broken.
On the other hand, are you absolutely *sure* you didn't have
the equivalent of

typedef int FOO *bar;

#define FOO

int main()
{
bar baz;
baz = (int*)0;
}

in your real code? Because that /isn't/ valid C, even though

#define bar int FOO *
#define FOO

is.

You're spot-on. It turns out that I did indeed have the order mixed up
-- fixed that, and all is well.

Thank you very much ...

--Andrew
aek at pumpkininc dot com
 
A

aekalman

Eric Sosman said:
Not as far as I can see. With the latter definition
of OSLOC_ECB your sample usage goes

OStypeEcbP myEcbP;
-> OStypeEcb OSLOC_ECB * myEcbP;
-> OStypeEcb bank1 * myEcbP;

... which looks like nonsense, unless `bank1' is itself
#define'd to something, or unless it's a special beyond-
the-C-language extension recognized by the compiler at
hand. If there's another #define lurking somewhere you
haven't shown it (or I've overlooked it). If `bank1' is
a non-C extension keyword, then you need to address your
question to the non-C compiler.

I work with a multitude of C compilers for embedded targets, and
special memory qualifiers like bank1 / bank2 / bank3 (PIC16) and data
/ idata / xdata (8051) are de rigeur for processors with banked memory
schemes. My challenge is that some of the other targets (e.g. x86,
MSP430) have very nice linear memory spaces, and don't need such
qualifiers, yet a single code base must serve all targets and
compilers. So the preprocessor gets used a lot in my code ...

I apologize if this was off-topic for comp.lang.c. I approached it
from a perspective of general interest w/regard to the C preprocessor.

--Andrew
aek at pumpkin inc dot com
 
E

Eric Sosman

aekalman said:
I work with a multitude of C compilers for embedded targets, and
special memory qualifiers like bank1 / bank2 / bank3 (PIC16) and data
/ idata / xdata (8051) are de rigeur for processors with banked memory
schemes.

That's pretty much what I'd guessed. But since such
qualifiers are not part of the C language, but part of some
kind of "C with extensions" language, the question of whether
they can be part of a "type" (rather than just part of the
declaration of an identifier) is unanswerable in C, and is
entirely up to the vagaries of the compiler that supports
the extensions.

> My challenge is that some of the other targets (e.g. x86,
MSP430) have very nice linear memory spaces, and don't need such
qualifiers, yet a single code base must serve all targets and
compilers. So the preprocessor gets used a lot in my code ...

Understandable. Sometimes you can segregate a lot of the
platform details into a layer of "pluggable" functions, but
sometimes they poke through to the upper levels and need to
be dealt with.
I apologize if this was off-topic for comp.lang.c. I approached it
from a perspective of general interest w/regard to the C preprocessor.

One rather pedantic difficulty is that the C preprocessor
operates on tokens ("preprocessing tokens," actually) rather
than on text. Nowhere is it required that these tokens have
intelligible textual representations; it is legitimate for the
tokenization process to destroy information or to add information
that isn't readily "textualized." And the upshot of all this is
that there's no requirement that you be able to see the source
after preprocessing.

However, many or even most compilers *do* have some way of
generating a text representation of the preprocessed program,
and I still don't understand why the output yours produced
suggests that the preprocessor ignored a defined macro. It's
certainly un-C-like to do so, and may indicate a compiler bug.
If so, you need help from experts in that particular compiler,
not help with the C language itself. Good luck!
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top