On 09/04/2025 15:13, bart wrote:
On 09/04/2025 13:36, David Brown wrote:
On 09/04/2025 12:51, bart wrote:
[Restore previously clipped context]
Turning it around, you're saying that if T an U are incompatible types
within the same translation unit, they suddenly become compatible if
split across two translation units?
...
I'll have to think about this before replying to any other points.
>
Marvellous - I'd appreciate you putting more thought into this, and
less knee-jerk reactions and exaggerations. Please also read the
relevant parts of the standards before replying - at the very least,
section 6.2.7p1 and section 6.2.2. Once you have read these and tried
to understand them, it will be a lot easier to clear up any remaining
issues.
I'm not going to wade through reams of Standard minutiae, sorry.I
...
Are T and U compatible types are not? The answer must be unequivocal
without needing to be a 'standards-head'.
I have no idea what qualifies as being a "standards-head". However, it
does not take "reams of Standard minutiae" to answer that question, only
about one page, which I've quoted below.
The clipping that I restored above seems to be the complete definition
of T and U in this context. However, the problem doesn't come up in the
general case where T and U are incompatible types. It applies only to
struct, union, and enumeration types that are incompatible because they
occur in separate declarations in the same translation unit, and there
are additional requirements on those types listed below. The key
relevant clause is:
"Two declarations of structure, union, or enumerated types which ... use
different tags declare distinct types. Each declaration of a structure,
union, or enumerated type which does not include a tag declares a
distinct type." (6.7.2.3p9).
So if T and U are tags, they declare distinct types. If either one is a
typedef for a type declared without a tag, they are distinct types. Note
that types declared in different translation units are automatically
distinct types, because file scope is the largest scope that exists in
C, and it terminates at the end of a translation unit.
Now, because they are distinct types, the first sentence of 6.2.7
doesn't apply:
"Two types are compatible types if they are the same."
Therefore, you'll have to skip to the rest of 6.2.7:
"Moreover, two complete structure, union, or enumerated types declared
with the same tag are compatible if members satisfy the following
requirements:
— there shall be a one-to-one correspondence between their members such
that each pair of corresponding members are declared with compatible types;
— if one member of the pair is declared with an alignment specifier, the
other is declared with an equivalent alignment specifier;
— and, if one member of the pair is declared with a name, the other is
declared with the same name.
For two structures, corresponding members shall be declared in the same
order. For two unions declared in the same translation unit,
corresponding members shall be declared in the same order. For two
structures or unions, corresponding bit-fields shall have the same
widths. For two enumerations, corresponding members shall have the same
values; if one has a fixed underlying type, then the other shall have a
compatible fixed underlying type. For determining type compatibility,
anonymous structures and unions are considered a regular member of the
containing structure or union type, and the type of an anonymous
structure or union is considered compatible to the type of another
anonymous structure or union, respectively, if their members fulfill the
above requirements.
Furthermore, two structure, union, or enumerated types declared in
separate translation units are compatible in the following cases:
— both are declared without tags and they fulfill the requirements above;
— both have the same tag and are completed somewhere in their respective
translation units and they fulfill the requirements above;
— both have the same tag and at least one of the two types is not
completed in its translation unit.
Otherwise, the structure, union, or enumerated types are incompatible."
Pay close attention to the last three bullet items.
Whether or not T and U change from being incompatible to being
compatible if declared in different translation units depends upon
whether T and U are tags or typedefs. If T and U are both tags, only the
last two bullets can apply, and T and U remain incompatible even if
declared in different translation units.
However, If T and U are typedefs for types "declared without tags and
they fulfill the requirements above", then they qualify as compatible
types under the first bullet above.
Note that the length of this quotation is almost entirely taken up by
detailing "the requirements above" - but those requirements can be
summarized by saying that the declarations of the members are,
recursively, only permitted to be different by reason of specifying
distinct but compatible types.
...
This has been said in this
thread:
BC: The types involved are somewhat different, but are compatible enough
for it to work. [In that the member types, offsets and overall size,
since pass-by-value is used, correspond]
DB: The two types are entirely compatible.
BC: Are they?
TR: No, they are not.
You say they're compatible, Tim Rentsch says they're not; who's right?
I haven't seen Tim's contributions to this thread, so I can't be sure,
but since the answer depends upon whether they are tags or typedefs, I
would imagine that that distinction might be involve in that discrepancy.