What's the use of anonymous structs?

E

Eric Sosman

[...] And I believe anonymous structs were just missed here.
[...] nobody thought
about it or it was too much trouble to add it to the standard
comparing to the benefits.

Perhaps you should take your question to comp.std.c
instead. All I can offer is my opinion that nothing has
been "missed" and that effort has not been conserved by
avoiding "too much trouble." But that's just my opinion;
the people who actually did the work might agree with you.
 
E

Eric Sosman

Ben said:
Martien Verbruggen said:
struct date {int year; int month; int day;};
struct foo {int a; struct date; int b;};
[...]

It is a Microsoft extension to C. [...]

Why does Microsoft get the credit or blame for inventing
*everything*? I recall a DEC C compiler whose headers made
heavy use of this technique, back in the mid-1980's when Bill
was still a mere gazillionaire. Yes, even before he invented
the integrated circuit, Boolean algebra, Usenet, democracy, the
wheel, continental drift, and sex.
 
B

Ben Pfaff

Eric Sosman said:
Ben said:
Martien Verbruggen said:
On Wed, 17 Oct 2007 14:51:19 -0700,
struct date {int year; int month; int day;};
struct foo {int a; struct date; int b;};
[...]

It is a Microsoft extension to C. [...]

Why does Microsoft get the credit or blame for inventing
*everything*? [...]

Well, in this case I named Microsoft because it was named in the
GCC manual. I have no direct knowledge of the original source.
 
T

Thad Smith

Richard said:
Thad Smith said:
Fred said:
On 17 Oct 2007 at 21:45, Richard Heathfield wrote:
Fred Phillips said:
Title says ["What's the use of anonymous structs?"]
Sorry, I guess I wasn't clear. I mean things like
struct { int a; int b; } c;
which is certainly valid C. However, this anonymous struct doesn't seem
to be compatible with any other anonymous struct of the same signature.
I wrote some simulation code recently that had a large module with
many file scope variables containing various states of the simulation.
...
static struct {
double speed;
double torque;
double temp;
double current;
} motor;

This is pretty much exactly what structs are for. I'm not sure I
understand your point here unless it is to explain how to use structs?

Perhaps I didn't quote enough of the message I was responding to, in
which the OP was asking what use a struct without a tag has. I was
giving an example of such usage with my reason.
 
T

those who know me have no need of my name

in comp.lang.c i read:
But if C required all struct types to have a tag ("struct foo { ... }"),
it wouldn't have caused any real problems. In the few cases where the
tag name is irrelevant, you could just make up something arbitrary.

but which must not be the same as any other such invention (in the same or
subordinate scope). annoying. i'm perfectly happy they can be left unnamed.
 
D

David Thompson

Well, the "compatible" there is italicized, I take it as
that's the definition of "compatible". In other words, it

But the definition includes the rest of para 1, and the other paras
referred to; it must, otherwise these statements, which are stated as
requirements in the standard, would be inconsistent with the
definition and thus no implementation of C would be possible. And we
know it can't be the intent of the Standard writers to prevent all
implementations and therefore all use of the language. (In spite of
exaggerated and insulting conspiracy theories from some.)
says something like "Types are compatible if and only if
they are the same". And then it goes to explain what it
means for two types to be "the same".
Compatibility is deliberately weaker than being the same.
If two types are the same they are compatible; if they are distinct,
but are _sufficiently similar_ according to the specific rules given
in the rest of para 1 and the other paras, they are compatible.

Informally, compatibility of X and Y means that an (actual) X can
safely be accessed as a Y and it will work. This means compatible
types must have the same layout (representation) in storage, and types
that don't have the same representation can't be compatible. However
the converse (or inverse? I always forget) is not true: there are
(pairs of) types that are required to have the same representation(s),
but are still distinct types so that the compiler can (and usually
must) diagnose type-mixings considered undesirable.
But it makes stuff like

struct {int a; int b;} a;
struct {int a; int b;} *p = &a;

illegal, or, more realistic,

void callback (void *p)
{
struct {int a; int b;} *data = p;
/* ... */
}

void func (void)
{
struct {int a; int b;} data = {1, 2};
call_something (callback, &data);
}
Indeed it does. Declare the struct tag, or a typedef for the untagged
struct, once, somewhere visible to all uses -- which if it is used in
multiple functions means the declaration must be at file scope. That's
the rule. Or if you want to cheat, learn to live with the warnings and
override the errors. That's the way it is.
// file.h
extern struct {int a; int b;} *a;

It's impossible to actually define that 'a' if you include
the header into the C file; and it's possible all right if
you don't. Weird example of course, and it's why (it's a
hypothesis) this wasn't taken into account - nobody thought
about it or it was too much trouble to add it to the standard
comparing to the benefits.
Yes, that's a mildly unfortunate consequence of the rules adopted to
handle the cases considered more important.

This simple but fairly common case -- exactly one variable of or using
the type -- can be done by preprocessor trickery, if init to 0 is OK:

BLECH struct { blah blah } gorp;
where BLECH is #define'd as extern for all #include's of file.h EXCEPT
the one where you want to define the data; there is it #define'd
empty, which makes this a tentative definition, and since there can't
be another compatible declaration with initializer in that t.u. it
becomes an actual definition, and the one definition needed.
(Use a more mnemonic name, of course, depending on which
characteristic you want to emphasize and document: something like
ALLOC_OR_SHARE or something like GLOBAL_SINGLE_DATUM.)

For init to non-0, but known, you can use a macro that generates
either the correct initializer or no initializer.

But more generally you indeed cannot have two anonymous struct types
declared in the same t.u. with the same contents be the same type.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 
F

Francine.Neary

Cross-module compatibility addresses a nasty issue
that confronts many separately-compilable languages. If
the compiler processes module A on Tuesday and processes
module B on Wednesday, we can't really talk about a type
compiled in A being "the same" as a type declared in B.
And yet, we want A to create objects of type T and pass
them to B to be processed. Since A and B had separate
declarations for T they can't really have "the same" T,
so the Standard resorts to this notion of "compatibility"
to allow separately-compiled modules to agree on what a
T looks like.

Does that mean that the compiler is obliged to use the same memory
layout (i.e. same amount of padding in the same places) for two
structs with identical fields declared in different translation units?
What about if one of the fields has a different name (but the same
type) in the two structs?

If the answer to the first question is "yes", does that create
practical problems when trying to link object files created with
different C compilers (or the same compiler with different
optimization or other settings)?
 
E

Eric Sosman

Does that mean that the compiler is obliged to use the same memory
layout (i.e. same amount of padding in the same places) for two
structs with identical fields declared in different translation units?
What about if one of the fields has a different name (but the same
type) in the two structs?

If the struct tags are different, the types are different.
You can test this for yourself:

struct A { int i; } a = { 42 };
struct B { int i; } b;
b = a; /* diagnostic required */

Since the two structs are of different types, they could
in theory have different representations: The Standard requires
common representations for only a few sets of types, and these
are not among them. In practice, though, the compiler will
process the `struct A' and `struct B' declarations with the
same algorithm and get the same result (in the absence of
things like `#pragma pack' and similar bletcherous botches).
If the answer to the first question is "yes", does that create
practical problems when trying to link object files created with
different C compilers (or the same compiler with different
optimization or other settings)?

There *are* practical problems in linking objects from
different compilers. As for option flags, if they make the
compiler behave differently, then what you've really got is
one piece of software that several different compilers. For
example, if there's a `--pack-all-structs' option, you can
expect trouble mixing modules compiled with and without it.
 
F

Francine.Neary

If the struct tags are different, the types are different.
You can test this for yourself:

struct A { int i; } a = { 42 };
struct B { int i; } b;
b = a; /* diagnostic required */

Since the two structs are of different types, they could
in theory have different representations: The Standard requires
common representations for only a few sets of types, and these
are not among them. In practice, though, the compiler will
process the `struct A' and `struct B' declarations with the
same algorithm and get the same result (in the absence of
things like `#pragma pack' and similar bletcherous botches).

I guess I was asking specifically about un-named structs in different
translation units. Consider the following code:


/* TU1.c */

void foo(struct { int a; })
{
...
}


/* TU2.c */

void foo(struct { int a; });
void bar()
{
struct { int a; } X;
X.a=0;
foo(X);
}


/* TU3.c */

void foo(struct { int a; });
void baz()
{
struct { int a; } Y;
Y.a=0;
foo(Y);
}

If I understood what you said upthread correctly, this will work just
fine, though if foo were actually defined in TU2.c then there'd be a
type-incompatibility and TU2.c wouldn't compile.

Doesn't this force binary compatibility between objects of any unnamed
types struct { int a; } in different translation units? (But not
necessary between an object of a type struct { int a; } and an object
of a type struct { int b; } ?)
 
E

Eric Sosman

I guess I was asking specifically about un-named structs in different
translation units. Consider the following code:


/* TU1.c */

void foo(struct { int a; })

Needs an identifier after the } -- let's call it tu1.
{
...
}


/* TU2.c */

void foo(struct { int a; });
void bar()
{
struct { int a; } X;
X.a=0;
foo(X);

Diagnostic required. The declared type of the parameter
to foo() is different from that of X, and no conversion is
possible. You've got two untagged struct types in the same
translation unit; the compatibility rule for untagged structs
specifically requires separate translation units.

Within one translation unit, each struct declaration
introduces a new type, distinct from all other types. For
structs with tags the scope rules apply: Two identically-
tagged structs in disjoint scopes are different types, while
two identically-tagged structs in overlapping scopes provoke
a diagnostic. For untagged structs, the behavior is as if
the compiler gave the first one an artificial tag like `#1',
the next one `#2', and so on: Each untagged struct is a distinct
type, no matter what the scope, and two such struct types can
never be compatible.

Some compilers will emit a helpful warning about the
declaration of foo(), pointing out that the struct type has
"prototype scope." That is, the type goes out of scope at
the end of the prototype, meaning that any similar struct you
might declare elsewhere will be in a different scope and will
not be of the same type. Thus, there is no way to write a
correct call to foo() in the same translation unit because
there is no way to declare an argument of the proper type.
}


/* TU3.c */

void foo(struct { int a; });
void baz()
{
struct { int a; } Y;
Y.a=0;
foo(Y);

Same problem as before: Two untagged structs in the same
translation unit are two distinct types.
}

If I understood what you said upthread correctly, this will work just
fine, though if foo were actually defined in TU2.c then there'd be a
type-incompatibility and TU2.c wouldn't compile.

Doesn't this force binary compatibility between objects of any unnamed
types struct { int a; } in different translation units? (But not
necessary between an object of a type struct { int a; } and an object
of a type struct { int b; } ?)

I think you should re-read 6.2.7p1, and then if necessary
take a deep breath and read it yet again. Question 11.5 in
the FAQ may also be helpful.
 

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

No members online now.

Forum statistics

Threads
474,444
Messages
2,571,709
Members
48,796
Latest member
Greg L.
Top