Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

typedef struct problem

185 views
Skip to first unread message

Jeff Lacki

unread,
Nov 20, 2000, 3:00:00โ€ฏAM11/20/00
to
Ok, this *should* have been easy but turning out not so.

Im using RH 6.2 gcc -v:
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)

code:

// user configuration reader/writer/parser file

#include <stdio.h>
#include <string.h>

#define BUF_SIZE 80
#define KEY_LEN_MAX 20 // max key char len
#define VAL_LEN_MAX 20

#define U_CONFIG_KEY_VALUE_MAX 3

typedef struct u_config_str
{
char key[KEY_LEN_MAX];
char value[VAL_LEN_MAX];
}; <--- line 16

u_config_str user_config[U_CONFIG_KEY_VALUE_MAX] = <--- line 18
{
<snip>

config.c:16: warning: useless keyword or type name in empty declaration

So then, if I add a dummy var in there, such as:
} dummy; <-- line 16
my first error now becomes:

config.c:18: parse error before `user_config'

is this wacked? I thought I could typedef a struct (which I know I
can) and use it later? Apparently not in this case.

Also I tried using all caps for the typedef name u_config_str. In that
case I get the same error as before on line 16:
config.c:16: warning: useless keyword or type name in empty declaration

Anyone have this problem and know the solution? I almost think its
a bug in gcc 2.91

Thanks
Jeff

Tim Hockin

unread,
Nov 20, 2000, 7:18:43โ€ฏPM11/20/00
to
Jeff Lacki <je...@rahul.net> wrote:
: typedef struct u_config_str

: {
: char key[KEY_LEN_MAX];
: char value[VAL_LEN_MAX];
: }; <--- line 16


do you mean

typedef struct {
...
} u_config_str;


?

--
Tim Hockin
tho...@isunix.it.ilstu.edu
This program has been brought to you by the language C and the number F.
ZZ

Gergo Barany

unread,
Nov 20, 2000, 7:51:40โ€ฏPM11/20/00
to
Jeff Lacki <je...@rahul.net> wrote:
> typedef struct u_config_str
> {
> char key[KEY_LEN_MAX];
> char value[VAL_LEN_MAX];
> }; <--- line 16

This is syntactically wrong. A declaration of the type

struct foo
{
int bar;
};

creates a type called "struct foo". To create a typedef, you have to
use

typedef struct foo_optional
{
int bar;
} foo;

If foo_optional is present, it creates a type called "struct
foo_optional", otherwise it's an anonymous struct. It also creates
an alias (the typedef) called "foo" that is synonymous to the
aforementioned struct.
(foo_optional and foo can be the same name because they are in
different namespaces. So typedef struct foo {...} foo; is legal.)

> u_config_str user_config[U_CONFIG_KEY_VALUE_MAX] = <--- line 18
> {
> <snip>
>
> config.c:16: warning: useless keyword or type name in empty declaration

Yes, because your declaration above was missing the name to typedef
(as if you had written, for instance, "typedef int ;").

> So then, if I add a dummy var in there, such as:
> } dummy; <-- line 16

This creates a typedef called "dummy". Your struct can now be called
"dummy" or "struct u_config_str".

> my first error now becomes:
>
> config.c:18: parse error before `user_config'

That's because there is no type called u_config_str. Change your
struct declaration to

typedef struct u_config_str
{
char key[KEY_LEN_MAX];
char value[VAL_LEN_MAX];

} u_config_str;

Now you can call it "struct u_config_str" or just plain
"u_config_str", and everything should be peachy.

Gergo

--
The world wants to be deceived.
-- Sebastian Brant

Steven Huang

unread,
Nov 20, 2000, 7:54:20โ€ฏPM11/20/00
to
In article <8vcdm8$3g5$1...@samba.rahul.net>,
Jeff Lacki <je...@rahul.net> wrote:
[...]

> typedef struct u_config_str
> {
> char key[KEY_LEN_MAX];
> char value[VAL_LEN_MAX];
> }; <--- line 16
>
> u_config_str user_config[U_CONFIG_KEY_VALUE_MAX] = <--- line 18
[...]

> config.c:16: warning: useless keyword or type name in empty
> declaration
>
> So then, if I add a dummy var in there, such as:
> } dummy; <-- line 16
> my first error now becomes:
>
> config.c:18: parse error before `user_config'
[...]

There are two declarations here:

1. typedef <something> typedef_name;
2. struct [struct_name] <something> (where struct_name is
optional).

that can be combined as:

typedef (struct [struct_name] <something>) typedef_name;

What you did was to supply struct_name, which is optional, but
fail to supply typedef_name, which is not. Writing it this way
may help you understand it better:

struct foo_struct {
...
}; /* declares struct foo_struct */
typedef struct foo_struct foo_type; /* alias for foo_struct */

foo_type foo1; /* create a foo_type */
struct foo_struct foo2; /* create a foo_struct */

> Also I tried using all caps for the typedef name u_config_str.

Programming should not be a matter of trial and error. This
approach is dangerous, because you would not learn whether it
"works" only because your current compiler fails to catch the
error for you, or whether it works because it should.

You *need* a good tutorial book in C, and a good reference book.
Consult the comp.lang.c FAQ for suggestions.

[...]


> Anyone have this problem and know the solution? I almost think
> its a bug in gcc 2.91

Compilers are not infallible, but the odds of a mature compiler
choking on a simple construct are low.


Sent via Deja.com http://www.deja.com/
Before you buy.

Chris Torek

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
In article <8vcdm8$3g5$1...@samba.rahul.net> Jeff Lacki <je...@rahul.net> writes:
>typedef struct u_config_str {
> char key[KEY_LEN_MAX];
> char value[VAL_LEN_MAX];
>};

You are using what I called "the combo thing" in another article
in this newsgroup. As I noted there, I hate "the combo thing";
I think all it does is confuse people.

Several followups have claimed that this is syntactically incorrect.
Technically it is okay syntactically, but fails to meet a constraint
(original ANSI edition, section 3.5, "Declarations", p. 58, l. 16).
Of course, either way, it requires a diagnostic from any ANSI/ISO
C compiler.

The syntax for a structure definition is:

struct tag_you_invent {
/* members go here */
};

The "structure tag" itself is optional, but if you leave it out,
the structure has no *name*. For various reasons, C lets you do
it, sometimes even usefully, but it makes it very hard to talk
about your code. This is a bad situation to be in, so always use
a tag. (In this case, you used the tag "u_config_str", which is
fine.)

To declare a structure without defining it, you can write:

struct mytag;

and in either case, after you have invented a tag and defined the
structure (e.g., "struct mytag { int x; };"), you can define
variables of that type:

struct mytag var1, var2;

Aside from one special case, every occurrence of "struct mytag"
now refers back to the same structure definition. For this article
I will ignore the special case entirely.

Now, the "typedef" keyword is highly misleading. The very name
"typedef" makes it "obvious" that it "def"ines a "type" -- but it
does not do so at all! All "typedef" does is make an "alias" --
an extra name -- for some existing type.

The syntax for typedef is just like that for ordinary variable
declarations. In fact, syntactically speaking, the keyword is
treated as if it were a "storage class specifier" like "static".
Where you would normally write:

int x, *y, z[3];

you can stick the typedef keyword in the front:

typedef int x, *y, z[3];

The keyword converts "ordinary variable declarations" into "typedef
declarations": each name becomes an alias for the type that the
variable *would have had*, if it were an actual variable.

Thus, since x would have been an ordinary "int", the name "x" now
becomes an alias for "int". Since y would have been an ordinary
"int *" (pointer to int), the name "y" becomes an alias for "int
*". Since z would have been an "array 3 of int", z becomes an
alias for "int [3]". Now you can write:

z somevar;

to declare "int somevar[3]", for instance.

Let me say that again: TYPEDEF DOES NOT DEFINE A TYPE. That the
keyword that defines an alias is spelled "typedef" instead of
"aliasdef" is really weird and obnoxious, but we are stuck with
it. You just have to memorize it: "The keyword is spelled wrong;
typedef does not define a type; typedef defines an alias."

The syntax is exactly the same for structures:

typedef struct mytag x, *y, z[3];

declares the identifiers x, y, and z as aliases for existing types:
"struct mytag", "struct mytag *", and "struct mytag [3]" respectively.

Now, what about this "typedef struct u_config_str { ... };"? This
is what I called "the combo thing". You are allowed to take the
two separate constructs:

struct u_config_str { ... };

and:

typedef struct u_config_str x, *y, z[3];

and glue them up into one big, hairy, hard-to-understand mess.
Combining the two saves you a few key-presses, of course, and it
has some special properties when dealing with untagged structures.
Some people like it, but I am not one of them.

Not entirely incidentally, people who like typedefs often try
to use them to make linked-list data structures. A linked list
of <key, value> pairs might look like this:

struct list {
int key, value;
struct list *next;
};

If for some reason you wanted to make a typedef named LIST that
is an alias for "struct list", you might write:

struct list {
int key, value;
LIST *next; /* WRONG */
};
typedef struct list LIST;

but this does not work, because the typedef name (LIST) has not
been declared at the point where it is first used. Even using
"the combo thing" does not help, because the typedef name *still*
appears too late:

typedef struct list {
int key, value;
LIST *next; /* still WRONG */
} LIST;

Of course, writing out "struct list" works:

struct list {
int key, value;
struct list *next;
};
typedef struct list LIST;

If you eschew "the combo thing", though, you can in fact make the
"LIST *next" part right! Consider:

typedef struct list LIST;
struct list {
int key, value;
LIST *next; /* how about that! */
};

In this case, you have defined the type-alias ("typedef") name
*first*, and only then gotten around to defining the structure.
This is okay, because naming a structure that has been declared
but not yet defined is okay in C. (It gives you something called
an "incomplete type". You can do a lot with incomplete types, and
to do the rest, you just have to "complete" them. Defining "struct
list" completes the structure type, and since LIST is just an alias
for the structure type, as soon as the structure type itself is
complete, LIST becomes an alias for a complete type.)

Incidentally, in C++, class and struct declarations have an
"automatic self-typedef", as it were. Any time you write:

struct mytag {

a C++ compiler acts a lot like a C compiler would have if you
had written:

typedef struct mytag mytag; struct mytag {

Note that the C++ compiler puts the typedef in *first*, so that
you can use the name inside the structure members. If you are
going to use typedefs at all in C, you can do this too. You just
have to stop using "the combo thing".

(As for myself, I dislike C's typedefs, in a vague sort of way.
For the most part, "typedef struct mytag mytag" does nothing but
save you the effort of writing "struct" in front of "mytag". I
prefer to see the "struct" keyword, because it makes the syntax
obvious. Whether an identifier is meant as a typedef name or an
ordinary identifier is sometimes very hard to tell, and the ANSI
C standard actually has a special rule for one worst-case situation:

In a parameter declaration, a single typedef name
in parentheses is taken to be an abstract declarator
that specifies a function with a single parameter, not
as redundant parentheses around the identifier for
a declarator.

See section 3.5.4.3, "Function Declarators (Including Prototypes)",
p. 69, ll. 2--4, of the original 1989 ANSI edition. If you go easy
on the typedefs, you will not have to worry about this impenetrable
quote.)

Summary (for anyone who read this far):

- THE typedef KEYWORD DOES NOT DEFINE A TYPE. Bizarre,
but you just have to get used to it: typedef defines
an alias, not a new type.

- Syntactically, typedef is a storage-class specifier,
so you could use "the combo thing"; but you should not
because it will just confuse you. Moreover:

- If you are going to use a typedef for a structure
type, put the typedef in FIRST, and *then* define
the structure type. This lets you use the typedef
name inside the definition, and keeps you from confusing
yourself with the combo thing.
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA, USA Domain: to...@bsdi.com +1 510 234 3167
http://claw.bsdi.com/torek/ (not always up) I report spam to abuse@.

Mark A. Odell

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to

"Chris Torek" <to...@elf.bsdi.com> wrote in message
news:8vdu66$ba7$1...@elf.bsdi.com...

> In article <8vcdm8$3g5$1...@samba.rahul.net> Jeff Lacki <je...@rahul.net> writes:
> >typedef struct u_config_str {
> > char key[KEY_LEN_MAX];
> > char value[VAL_LEN_MAX];
> >};
>
> You are using what I called "the combo thing" in another article
> in this newsgroup. As I noted there, I hate "the combo thing";
> I think all it does is confuse people.

No, he has an error. It should have been

typedef struct ObjectStruct
{
/* elements */
} Object;

Now define one of these:

Object obj; [1]

or

struct ObjectStruct obj2; [2]

I agree, drop the tag and just use the typedef (as in [1]).

> Now, the "typedef" keyword is highly misleading. The very name
> "typedef" makes it "obvious" that it "def"ines a "type" -- but it
> does not do so at all! All "typedef" does is make an "alias" --
> an extra name -- for some existing type.

No, it is not an alias it is a new type.

I'll emulate hardware registers with a struct.
typedef struct
{
unsigned long readReg; /* read-only at 0xFFF00000 */
unsigned long writeReg; /* write-only at 0xFFF00000*/
} Reg;

Reg fakeRegs;
volatile Reg *pReg = &fakeRegs;

unsigned long var = pReg->readReg;
pReg->writeReg = 0xA5UL;
...
many more lines of code.


Now when I get the real hardware mapped in I change two things:
typedef struct --> typedef union
-and-
volatile Reg *pReg = HW_REG_PHYS_ADDR;

A trivial example here, but the point is that the typedef
helps to hide unnessecary data from me.

> you can stick the typedef keyword in the front:
>
> typedef int x, *y, z[3];

Really? This doesn't look right.

Typedef int x;
x *y, z[3];

will work.

> - THE typedef KEYWORD DOES NOT DEFINE A TYPE. Bizarre,
> but you just have to get used to it: typedef defines
> an alias, not a new type.

It does define a new type. It is not an alias.

--
- Mark -> "It's in the Organization"
--

Chris Torek

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
>"Chris Torek" <to...@elf.bsdi.com> wrote in message
>news:8vdu66$ba7$1...@elf.bsdi.com...
>> You are using what I called "the combo thing" in another article
>> in this newsgroup. As I noted there, I hate "the combo thing";
>> I think all it does is confuse people.

In article <79vS5.15625$M51.4...@typhoon.ne.mediaone.net>


Mark A. Odell <ma...@foobar.nospam> writes:
>No, he has an error.

Huh? He *is* using "the combo thing"; are you denying that?

He does indeed have an error, but it is not a syntax error, it is
a constraint error. (This is purely a technical C-standards issue;
either way, it is an error.)

>It should have been
>
>typedef struct ObjectStruct
>{
> /* elements */
>} Object;

That is "the combo thing" again, and as I said, I hate that. It
*is* legal but it will just confuse you.

>Now define one of these:
>
>Object obj; [1]
>
>or
>
>struct ObjectStruct obj2; [2]
>
>I agree, drop the tag and just use the typedef (as in [1]).

You agree with whom? I prefer using the tag.

>> Now, the "typedef" keyword is highly misleading. The very name
>> "typedef" makes it "obvious" that it "def"ines a "type" -- but it
>> does not do so at all! All "typedef" does is make an "alias" --
>> an extra name -- for some existing type.

>No, it is not an alias it is a new type.

Sorry, you are wrong. Here is a direct quote from the ANSI C standard:

A typedef declaration does not introduce a new type,
only a synonym for the type so specified.

(ยง3.5.6, "Type Definition", p. 71, ll. 8--9 of ANSI Classic).

>I'll emulate hardware registers with a struct.
>typedef struct
>{
> unsigned long readReg; /* read-only at 0xFFF00000 */
> unsigned long writeReg; /* write-only at 0xFFF00000*/
>} Reg;

Your untagged structure definition creates a new type. Your typedef
(using "the combo thing", which has confused you) then *uses* that
new type, created by the untagged structure definition, and makes
an alias for that (now-existing) type.

The combo thing misled you into thinking that typedef defined a
new type. It did not; typedef used the type defined by the "struct"
keyword, and made a new name -- an alias -- for this old type.
Because you used an untagged structure, this is now the *only*
name for this type -- but it was the "struct {" sequence that
defined it, not the typedef.

(Incidentally, you could const-qualify the read-only register. There
is nothing you can do about the write-only register though.)

>Now when I get the real hardware mapped in I change two things:

>typedef struct --> typedef union ...

Then why did you use a "struct" in the first place? (Actually, I
suspect I know why, but I disagree with what I suspect is your answer;
read on. :-) )

If you want to test this stuff in a "fake hardware" environment, you
could then this:

/* typedef struct reg Reg; -- optional */
struct reg {
uint32_t csr; /* control and status */
uint32_t addr; /* bus address for DMA */
uint32_t bcnt; /* byte count for DMA */
};

#ifdef REAL_HW

#define READ_REG(regp, name) ((regp)->name)
#define WRITE_REG(regp, name, val) ((void)((regp)->name = (val)))

#else /* for development */

extern uint32_t simulate_read(struct reg *regp, size_t offset);
extern void simulate_write(struct reg *regp, size_t offset,
uint32_t val);
#define READ_REG(regp, name) simulate_read(regp, offsetof(regp, name))
#define WRITE_REG(regp, name, val) \
simulate_write(regp, offsetof(regp, name), val)

#endif /* REAL_HW */

The "simulate" functions do the obvious thing, and the macros
READ_REG and WRITE_REG guarantee that you do not attempt to read
a write-only register, or vice versa.

>A trivial example here, but the point is that the typedef
>helps to hide unnessecary data from me.

The typedef hides nothing that the "struct" exposes, with one
exception: it lets you change "struct" to "union", or vice versa.
But it is always possible to embed a union within a struct (or vice
versa) as its single member, so this merely saves you some keystrokes.

>> you can stick the typedef keyword in the front:
>>
>> typedef int x, *y, z[3];

>Really? This doesn't look right.

That is because you were misled, probably by the combo thing. Check
the C standard to be sure (I could be wrong, but I am not :-) ).

>Typedef int x;
>x *y, z[3];
>
>will work.

This does something completely different (after you fix the uppercase
"t"): it declares "x" as an alias for the type "int", and then
declares y and z as actual variables of type "int". The typedef
declares three aliases, and no actual variables.

>> - THE typedef KEYWORD DOES NOT DEFINE A TYPE. Bizarre,
>> but you just have to get used to it: typedef defines
>> an alias, not a new type.

>It does define a new type. It is not an alias.

See section 3.5.6. It is an alias; it is not a new type.

Mark A. Odell

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
"Chris Torek" <to...@elf.bsdi.com> wrote in message
news:8ve0av$bfd$1...@elf.bsdi.com...

> Huh? He *is* using "the combo thing"; are you denying that?

I've never heard of a C "combo thing". I deny nothing.

> He does indeed have an error, but it is not a syntax error, it is
> a constraint error. (This is purely a technical C-standards issue;
> either way, it is an error.)

> You agree with whom? I prefer using the tag.

Yuk. Style issue.

> Sorry, you are wrong. Here is a direct quote from the ANSI C standard:
>
> A typedef declaration does not introduce a new type,
> only a synonym for the type so specified.
>
> (ยง3.5.6, "Type Definition", p. 71, ll. 8--9 of ANSI Classic).

Hmm... so since I always omit the tag, I have a type, not
an alias? I can live with that.

> The combo thing misled you into thinking that typedef defined a
> new type. It did not; typedef used the type defined by the "struct"
> keyword, and made a new name -- an alias -- for this old type.
> Because you used an untagged structure, this is now the *only*
> name for this type -- but it was the "struct {" sequence that
> defined it, not the typedef.

Interesting.

> (Incidentally, you could const-qualify the read-only register. There
> is nothing you can do about the write-only register though.)

I do for the real hardware, for simulation with the struct I
need to write the read-only regs. for simulation.

> >Now when I get the real hardware mapped in I change two things:
> >typedef struct --> typedef union ...
>
> Then why did you use a "struct" in the first place? (Actually, I
> suspect I know why, but I disagree with what I suspect is your answer;
> read on. :-) )

Because a similation task sits writes the read-only elements of the
struct and and reads the write-only elements of the struct.

> If you want to test this stuff in a "fake hardware" environment, you
> could then this:
>
> /* typedef struct reg Reg; -- optional */
> struct reg {
> uint32_t csr; /* control and status */
> uint32_t addr; /* bus address for DMA */
> uint32_t bcnt; /* byte count for DMA */
> };
>
> #ifdef REAL_HW
>
> #define READ_REG(regp, name) ((regp)->name)
> #define WRITE_REG(regp, name, val) ((void)((regp)->name = (val)))

I don't do macros. Functions only and let the compiler inline
if it wants/can. In the end I'll be reading and writing the
memory mapped I/O.

> >typedef int x; <-- Fixed T to t.


> >x *y, z[3];
> >
> >will work.
>
> This does something completely different (after you fix the uppercase
> "t"): it declares "x" as an alias for the type "int", and then
> declares y and z as actual variables of type "int". The typedef
> declares three aliases, and no actual variables.

I expected to have a pointer 'y' to type x and an array 'z' of
three 'x' elements. How am I wrong?

Chris Torek

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
>"Chris Torek" <to...@elf.bsdi.com> wrote in message
>news:8ve0av$bfd$1...@elf.bsdi.com...
>>Huh? He *is* using "the combo thing"; are you denying that?

In article <lHvS5.15957$M51.4...@typhoon.ne.mediaone.net>


Mark A. Odell <ma...@foobar.nospam> writes:

>I've never heard of a C "combo thing". I deny nothing.

You deleted your sentence that began with "No, ...". The word "no"
was denying *some*thing; I remain confused as to what it was you were
denying. I defined the phrase "the combo thing" in the article you
were originally following-up; perhaps you should go re-read it. :-)

>>You agree with whom? I prefer using the tag.

>Yuk. Style issue.

Agreed. (A paraphrase of something Mark Brader once said or quoted:
"there are plenty of bad styles, but there is no single good style".
I prefer the tag, but recognize that other people prefer the typedef.)

>>... Here is a direct quote from the ANSI C standard:


>> A typedef declaration does not introduce a new type,
>> only a synonym for the type so specified.
>>(ยง3.5.6, "Type Definition", p. 71, ll. 8--9 of ANSI Classic).

>Hmm... so since I always omit the tag, I have a type, not
>an alias? I can live with that.

To be precise -- i.e., pedantically speaking -- you have an alias
for an otherwise unnameable type.

Pragmatically speaking, this is a bad situation because a lot of
C compilers spit out useless (or even entirely-wrong) error messages
when you make a mistake with one of these. (Some of the worse
embedded-systems C compilers -- and there are a lot of bad ones --
even dump core, in my experience. If you have seen such a C compiler
dump core for a simple syntax error, I would give about a 20% chance
that it is due to using a tagless structure or union.)

Always put in a tag; I promise it will not hurt one bit. :-) Then
you can separate the typedef from the struct-or-union definition.
This lets you put the typedef first, so that -- for those who like
typedefs anyway -- you can use the typedef name to make a linked
list, or tree, or whatever. Even if you do not need a tag, put it
in anyway, to keep those (bad) compilers from dumping core.

[on doing some embedded systems development:]

[Mark]


>>>Now when I get the real hardware mapped in I change two things:
>>>typedef struct --> typedef union ...

>>Then why did you use a "struct" in the first place? (Actually, I
>>suspect I know why, but I disagree with what I suspect is your answer;
>>read on. :-) )

>Because a similation task sits writes the read-only elements of the
>struct and and reads the write-only elements of the struct.

This is pretty much what I suspected. I claim there is a better way:

>> If you want to test this stuff in a "fake hardware" environment, you
>> could then this:
>>
>> /* typedef struct reg Reg; -- optional */
>> struct reg {
>> uint32_t csr; /* control and status */
>> uint32_t addr; /* bus address for DMA */
>> uint32_t bcnt; /* byte count for DMA */
>> };

(Your news reader seems to have eaten all my tabs. Tabs are set at
every 8th position.)

>> #ifdef REAL_HW
>>
>> #define READ_REG(regp, name) ((regp)->name)
>> #define WRITE_REG(regp, name, val) ((void)((regp)->name = (val)))
>
>I don't do macros. Functions only and let the compiler inline
>if it wants/can. In the end I'll be reading and writing the
>memory mapped I/O.

The macros have two advantages:

- They prevent you from writing the read-only register
and reading the write-only register. ("Const" can
give you the former but not the latter.)

- They let you simulate the hardware efficiently.

You deleted the "#else" cases, but the idea there is that
simulate_read() and simulate_write() -- which I would probably
really call simr32(), simw32(), etc., with simr16() for 16-bit
simulated reads, etc., in real simulation code -- can easily locate
the "simulated hardware" in question, and simulate it. This means
you do not *need* a separate "simulation task". If you want to
use one anyway (for whatever reason), you can it run much more
efficiently. This will speed your development significantly. (I
speak from experience -- "rapid turnaround" on a simulator or logic
analyzer makes things go *much* faster.)

(Device-register access macros can have additional advantages beyond
these two. For instance, if someone ever makes an I/O-mapped
version of the same device, they are easy to convert. They can,
with a bit more up-front complexity, also handle busses with
byte-swapping hardware, where the I/O device is little-endian and
the CPU is big-endian, or vice versa. The NetBSD and "new framework"
FreeBSD drivers use macros to access hardware, and as a result, a
single well-written driver can work on machines as disparate as
the i386, DEC Alpha, MIPS, SPARC, and Amiga.)

[my original example:]


>>>>typedef int x, *y, z[3];

[Mark, again]
>>>typedef int x;
>>>x *y, z[3];

>>This does something completely different (after you fix the uppercase


>>"t"): it declares "x" as an alias for the type "int", and then
>>declares y and z as actual variables of type "int". The typedef
>>declares three aliases, and no actual variables.

>I expected to have a pointer 'y' to type x and an array 'z' of
>three 'x' elements. How am I wrong?

You have a pointer "y" to type "int". (The name "x" is just an
alias for int. You can stuff any old int into *y, e.g., "*y = 12345;"
is legal, even if you meant for type "x" to have a limited set of
values that does not include 12345.) You have an array "z" of three
ints. This is not *wrong*, it is just *different*:

typedef int x, *y, z[3];

defines three aliases, and is exactly equivalent to:

typedef int x;
typedef int *y;
typedef int z[3];

Compare this with the "static" keyword, whose syntax is the same as
that for "typedef":

static int x, *y, z[3];

The semantics of typedef are just weird. (I suspect this is largely
because typedef was sort of an afterthought, stuck in as a quick
hack to clean up the semantics of "#define"d type-names. That is:

#define XTYPE int

works okay, as you can write:

XTYPE *y, z[3];

but:

#define TREETYPE struct tree *

fails miserably when used to declare multiple variables.)

Ben Pfaff

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
to...@elf.bsdi.com (Chris Torek) writes:

> In article <8vcdm8$3g5$1...@samba.rahul.net> Jeff Lacki <je...@rahul.net> writes:
> >typedef struct u_config_str {
> > char key[KEY_LEN_MAX];
> > char value[VAL_LEN_MAX];
> >};
>

> Several followups have claimed that this is syntactically incorrect.
> Technically it is okay syntactically, but fails to meet a constraint
> (original ANSI edition, section 3.5, "Declarations", p. 58, l. 16).
> Of course, either way, it requires a diagnostic from any ANSI/ISO
> C compiler.

I see no constraint violation here. The declaration declares a
tag, therefore it is not in violation of the constraint in
question. Can you clarify?

Mark A. Odell

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to

"Ben Pfaff" <pfaf...@msu.edu> wrote in message
news:87y9ydq...@pfaffben.user.msu.edu...

> > >typedef struct u_config_str {
> > > char key[KEY_LEN_MAX];
> > > char value[VAL_LEN_MAX];
> > >};

> I see no constraint violation here. The declaration declares a


> tag, therefore it is not in violation of the constraint in
> question. Can you clarify?

It's okay to use 'typedef' but not name it?

Ben Pfaff

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
"Mark A. Odell" <ma...@foobar.nospam> writes:

> "Ben Pfaff" <pfaf...@msu.edu> wrote in message
> news:87y9ydq...@pfaffben.user.msu.edu...
>

> > > >typedef struct u_config_str {
> > > > char key[KEY_LEN_MAX];
> > > > char value[VAL_LEN_MAX];
> > > >};
>

> > I see no constraint violation here. The declaration declares a
> > tag, therefore it is not in violation of the constraint in
> > question. Can you clarify?
>
> It's okay to use 'typedef' but not name it?

The constraint in question is:

A declaration shall declare at least a declarator, a tag,
or the members of a declaration.

There is a tag being declared.
--
"This is a wonderful answer.
It's off-topic, it's incorrect, and it doesn't answer the question."
--Richard Heathfield

Mark A. Odell

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to

"Ben Pfaff" <pfaf...@msu.edu> wrote in message
news:87pujpq...@pfaffben.user.msu.edu...

> > > > >typedef struct u_config_str {
> > > > > char key[KEY_LEN_MAX];
> > > > > char value[VAL_LEN_MAX];
> > > > >};
> A declaration shall declare at least a declarator, a tag,
> or the members of a declaration.
>
> There is a tag being declared.

Okay, then I ask if the typedef that was used is an error or
or is it benign?

Ben Pfaff

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
"Mark A. Odell" <ma...@foobar.nospam> writes:

> "Ben Pfaff" <pfaf...@msu.edu> wrote in message
> news:87pujpq...@pfaffben.user.msu.edu...

> > > > > >typedef struct u_config_str {
> > > > > > char key[KEY_LEN_MAX];
> > > > > > char value[VAL_LEN_MAX];
> > > > > >};

> > A declaration shall declare at least a declarator, a tag,
> > or the members of a declaration.
> >
> > There is a tag being declared.
>
> Okay, then I ask if the typedef that was used is an error or
> or is it benign?

I think that it is benign. I am hoping that Chris Torek will
speak up and clarify.
--
"I ran it on my DeathStation 9000 and demons flew out of my nose." --Kaz

Chris Torek

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
NOTE: this is now cross-posted to comp.std.c (perhaps I should have
redirected followups too?).

Background: the original code read:

typedef struct u_config_str {
char key[KEY_LEN_MAX];
char value[VAL_LEN_MAX];
};

In article <8vdu66$ba7$1...@elf.bsdi.com> I wrote:to...@elf.bsdi.com (Chris Torek) writes:
>>Several followups have claimed that this is syntactically incorrect.
>>Technically it is okay syntactically, but fails to meet a constraint
>>(original ANSI edition, section 3.5, "Declarations", p. 58, l. 16).
>>Of course, either way, it requires a diagnostic from any ANSI/ISO
>>C compiler.

In article <87y9ydq...@pfaffben.user.msu.edu>


Ben Pfaff <pfaf...@msu.edu> writes:
>I see no constraint violation here. The declaration declares a
>tag, therefore it is not in violation of the constraint in
>question. Can you clarify?

Hm, you may be right.

Specifically, the C89 standard says:

A declaration shall declare at least a declarator, a tag,

or the members of an enumeration.

(The C99 draft that I have has similar wording; there is an added
parenthetical comment that does not appear to change anything here.)

Syntactically, the code in question parses via the following
(I omit bits of the syntax that are not being used):

declaration:
declaration-specifiers init-declarator-list<opt>;

declaration-specifiers:
storage-class-specifier declaration-specifiers<opt>
type-specifier declaration-specifiers<opt>

storage-class-specifier:
typedef [keyword]

type-specifier:
struct-or-union-specifier

struct-or-union-specifier:
struct-or-union identifier<opt> { struct-declaration-list }

struct-or-union:
struct [keyword]

The identifier and the struct-declaration-list are the obvious ones.

Syntactically, then, this is a single declaration. Semantically,
though, it is "meant as" two separate declarations that have merely
been fused:

struct u_config_str { ... };
and: typedef struct u_config_str;

If it were two separate declarations, the second one would definitely
violate the constraint in ยง3.5. The comp.std.c question: does the
"fused" construct indeed escape that constraint, despite the useless
s-c-specifier? (I think I was wrong, and that it does escape that
constraint.)

The same question would apply to using any other s-c-specifier and
no declarators.

It might perhaps be better if the constraints also said:

Moreover, if a declaration uses a storage-class specifier,
it shall declare at least a declarator.

In this case, the code would indeed violate a constraint.

Morris M. Keesan

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
On 20 Nov 2000 23:55:52 GMT, Jeff Lacki <je...@rahul.net> wrote:
...
>#define KEY_LEN_MAX 20 // max key char len
...
> char key[KEY_LEN_MAX];

I don't have a C99 compiler handy, to test my reading of the standard,
but this doesn't really work, does it? Doesn't this expand to

char key[20 // max key char len];

?? Or do the C++ compilers operating as C compilers with non-standard
extended features actually recognize comments within macro definitions,
and not put them into the expansions?

--
Morris M. Keesan -- mke...@lucent.com
Lucent Technologies Software Products Group

Ben Pfaff

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
mke...@lucent.com (Morris M. Keesan) writes:

> On 20 Nov 2000 23:55:52 GMT, Jeff Lacki <je...@rahul.net> wrote:
> ...
> >#define KEY_LEN_MAX 20 // max key char len
> ...
> > char key[KEY_LEN_MAX];
>
> I don't have a C99 compiler handy, to test my reading of the standard,
> but this doesn't really work, does it? Doesn't this expand to
>
> char key[20 // max key char len];

No. Comments are recognized in phase 3, preprocessing directives
are executed in phase 4.

Douglas A. Gwyn

unread,
Nov 21, 2000, 3:00:00โ€ฏAM11/21/00
to
Chris Torek wrote:
> typedef struct u_config_str {
> char key[KEY_LEN_MAX];
> char value[VAL_LEN_MAX];
> };
> Ben Pfaff <pfaf...@msu.edu> writes:
> >I see no constraint violation here. The declaration declares a
> >tag, therefore it is not in violation of the constraint in
> >question.

Yes, and if there are no declarators then there is
no identifier to worry about being defined as a
typedef name, so 6.7.7 semantics are trivially met.

Clive D.W. Feather

unread,
Nov 22, 2000, 3:00:00โ€ฏAM11/22/00
to
In article <8ve6b4$bqp$1...@elf.bsdi.com>, Chris Torek <to...@elf.bsdi.com>
writes

>Background: the original code read:
>
> typedef struct u_config_str {
> char key[KEY_LEN_MAX];
> char value[VAL_LEN_MAX];
> };

Similar code came up at a WG14 meeting. We couldn't see any easy way to
reword the rule to make this sort of thing illegal without also ruling
out useful code. Since it's harmless, we let it remain legal.

>It might perhaps be better if the constraints also said:
>
> Moreover, if a declaration uses a storage-class specifier,
> it shall declare at least a declarator.
>
>In this case, the code would indeed violate a constraint.

typedef struct {
void (*foo) (int x);
}

would be legal, because it declares the declarator x, but the code would
be illegal if the x were omitted !

--
Clive D.W. Feather | Internet Expert | Work: <cl...@demon.net>
Tel: +44 20 8371 1138 | Demon Internet | Home: <cl...@davros.org>
Fax: +44 20 8371 1037 | Thus plc | Web: <http://www.davros.org>
Written on my laptop; please observe the Reply-To address

Joona I Palaste

unread,
Nov 22, 2000, 3:00:00โ€ฏAM11/22/00
to
Clive D.W. Feather <cl...@on-the-train.demon.co.uk> scribbled the following
on comp.lang.c:

> In article <8ve6b4$bqp$1...@elf.bsdi.com>, Chris Torek <to...@elf.bsdi.com>
> writes
>>Background: the original code read:
>>
>> typedef struct u_config_str {
>> char key[KEY_LEN_MAX];
>> char value[VAL_LEN_MAX];
>> };

> Similar code came up at a WG14 meeting. We couldn't see any easy way to


> reword the rule to make this sort of thing illegal without also ruling
> out useful code. Since it's harmless, we let it remain legal.

>>It might perhaps be better if the constraints also said:
>>
>> Moreover, if a declaration uses a storage-class specifier,
>> it shall declare at least a declarator.
>>
>>In this case, the code would indeed violate a constraint.

> typedef struct {
> void (*foo) (int x);
> }

> would be legal, because it declares the declarator x, but the code would
> be illegal if the x were omitted !

How so? I tried the following programs:

/* Program 1 */


typedef struct {
void (*foo) (int x);

};
int main(void)
{ return 0; }

/* Program 2 */
typedef struct {
void (*foo) (int);
};
int main(void)
{ return 0; }

/* Program 3 */


typedef struct {
void (*foo) (int x);

} mystruct;
int main(void)
{ return 0; }

/* Program 4 */
typedef struct {
void (*foo) (int);
} mystruct;
int main(void)
{ return 0; }

All programs compiled without errors. Programs 1 and 2 gave a warning:
Unnamed struct/union that defines no instances
but anyway they succeeded in producing an executable.

What I think is happening is that the program includes a structure
definition, and that structure has exactly one field. This field is
called foo, and it is of type "pointer to function returning void,
taking one int parameter". The identifier x plays no role whatsoever
in this definition.
The structure is either unnamed and that's it (in programs 1 and 2), or
unnamed and aliased to "mystruct" (in programs 3 and 4).
I agree wholeheartedly with Chris Torek's claim that typedef doesn't
define a new type. I say so, Chris Torek says so, the ISO C standard
says so, even plain intuition says so. How could it not be so?

--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #80 D+ ADA N+++ |
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/

"'It can be easily shown that' means 'I saw a proof of this once (which I didn't
understand) which I can no longer remember'."
- A maths teacher

John Hauser

unread,
Nov 22, 2000, 3:00:00โ€ฏAM11/22/00
to

Chris Torek:

> It might perhaps be better if the constraints also said:
>
> Moreover, if a declaration uses a storage-class specifier,
> it shall declare at least a declarator.

Clive D.W. Feather:


>
> typedef struct {
> void (*foo) (int x);
> }
>
> would be legal, because it declares the declarator x, but the code
> would be illegal if the x were omitted !

Joona I Palaste:


> How so? I tried the following programs:

> [...]

Clive was responding to Chris's suggestion to change the Standard. Of
course his example is not _currently_ illegal even if the x is omitted.

- John Hauser

Joona I Palaste

unread,
Nov 22, 2000, 3:00:00โ€ฏAM11/22/00
to
John Hauser <jha...@cs.berkeley.edu> scribbled the following
on comp.lang.c:

> Chris Torek:

Note to self: Read whole threads.
Sorry Clive!

Richard Heathfield

unread,
Nov 22, 2000, 3:00:00โ€ฏAM11/22/00
to
Joona I Palaste wrote:

<snip>

> I agree wholeheartedly with Chris Torek's claim that typedef doesn't
> define a new type. I say so, Chris Torek says so, the ISO C standard
> says so, even plain intuition says so. How could it not be so?

Never mind those sources. Go straight to the ultimate authority:

"C allows you to define explicitly new data type names by using the
keyword *typedef*. You are not actually /creating/ a new data class, but
rather defining a new name for an existing type."

- "C - The Complete Reference", 2nd Edition, by Herbert Schildt

<g,d&rvf!>

--
Richard Heathfield
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton

Chris Torek

unread,
Nov 22, 2000, 3:00:00โ€ฏAM11/22/00
to
>In article <8ve6b4$bqp$1...@elf.bsdi.com>, Chris Torek <to...@elf.bsdi.com>
>writes
>>Background: the original code read:
>>
>> typedef struct u_config_str {
>> char key[KEY_LEN_MAX];
>> char value[VAL_LEN_MAX];
>> };

In article <4eP4fPDi...@romana.davros.org>


Clive D.W. Feather <cl...@demon.net> writes:
>Similar code came up at a WG14 meeting. We couldn't see any easy way to
>reword the rule to make this sort of thing illegal without also ruling
>out useful code. Since it's harmless, we let it remain legal.

That makes sense, but then it seems odd that:

static;

and:

int;

should be illegal, since they amount to the same idea. :-) (I note
that many K&R-1 compilers accepted both of these.)

>>It might perhaps be better if the constraints also said:
>> Moreover, if a declaration uses a storage-class specifier,
>> it shall declare at least a declarator.

>>In this case, the code would indeed violate a constraint.

[But even then]


>typedef struct {
> void (*foo) (int x);
>};
>would be legal, because it declares the declarator x, but the code would
>be illegal if the x were omitted !

Well, this is odd too, but perhaps no worse than what we have now. :-)

Hm. Perhaps:

Moreover, if a declaration uses a storage-class specifier,

it shall declare a declarator that is modified by that
storage-class specifier

would do the trick? (I can see that coming up with proper wording
is nontrival....)

Clive D.W. Feather

unread,
Nov 22, 2000, 3:00:00โ€ฏAM11/22/00
to
In article <8vgc55$e5i$1...@elf.bsdi.com>, Chris Torek <to...@elf.bsdi.com>
writes

>>Similar code came up at a WG14 meeting. We couldn't see any easy way to
>>reword the rule to make this sort of thing illegal without also ruling
>>out useful code. Since it's harmless, we let it remain legal.
>
>That makes sense, but then it seems odd that:
>
> static;
>
>and:
>
> int;
>
>should be illegal, since they amount to the same idea. :-)

This leads to the famous "thin ice" footnote.

Of course, these *are* easy to rule out, by including the present
requirement in the Standard.

>(I can see that coming up with proper wording
>is nontrival....)

You're learning :-)

0 new messages