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