I don't see what that has to do with anything. Even types which are
compatible and therefore interchangeable can be passed using different
registers.
It seemed perfectly obvious to me what interchangeability means, but if
you can actually believe that the above sentence makes any sense
whatsoever, we must differ in our understanding of that term at a very
fundamental level. To figure out where our understandings differ, I'm
going to have to explain my own understanding in tedious detail; feel
free to explain your own understanding of the term in similar detail, or
simply identify the differences.
There are seven cases where the standard currently requires "same
representation and alignment" (and incorrectly suggests in non-normative
footnotes that this implies interchangeability as arguments to
functions, return values from functions, and members of unions):
6.2.5p13: "D _Complex" and "D[2]", where D can be float, double, or long
double.
6.2.5p26: "T" and cv T", where T can be any type mentioned before
earlier in that same section, and cv is "const", "volatile", or both.
6.2.5p27:
void*, char*, unsigned char*, signed char*.
"cv1 T1*" and "cv2 T2*", where T1 and T2 are compatible types, and cv1
and cv2 can each be const, volatile, const volatile, or absent.
"struct tag1*" and "struct tag2*"
"union tag3*" and "union tag4*"
G4: "D _Imaginary" and "D"
A type obviously has the same representation and alignment with itself;
less obviously, but explicitly stated in the standard, a type is always
compatible with itself. For most of the cases above where the two types
are different, the types are not compatible. The one exception I could
identify: if cv1==cv2, but T1!=T2, cv1 T1 and cv2 T2 are different but
compatible types. Furthermore, most of those cases do not allow for
implicit conversion - the exception being those involving qualifiers.
Whenever a pair of SRAR types is not compatible and have no implicit
conversions between them, using one in place of the other is generally
at least a constraint violation, and otherwise has undefined behavior (I
didn't notice any cases where it has implementation-defined behavior,
but I may have missed a case).
If it's a constraint violation, the implementation is required to
diagnose the program, and is not required to translate or execute it.
Therefore, it seems to me that interchangeability, if it were indeed
implied by SRAR, would be meaningful only in those cases which have
undefined behavior. It can only mean that, despite the fact that the
behavior is undefined by the standard, the forms of behavior that are
actually possible are constrained by the fact that they are SRAR types,
to produce the expected results.
By "expected results", I mean the following: for pointers, the pointer
value received will point at the same location in memory, though with a
different type. For _Complex, the corresponding array of double will
contain the real and imaginary components of the complex number. For
_Imaginary, the corresponding real value will be the same as the
imaginary component of the the _Imaginary one. For the cases which
differ in cv-qualification, the values will be the same as if by
implicit conversion.
For interchangeability as function arguments:
6.5.2.2p6:
a) A function is called with a K&R style declaration in scope. The
promoted type of an argument passed to the function is not compatible
with the type of the corresponding parameter in the function's
definition, but they are SRAR types.
b) A function is called with a prototype that ends with an ellipsis,
follows those same rules with respect to parameters after the last
declared parameter.
Note that this clause contains an exception that says, in effect, that
void* and pointers to character types are interchangeable - but only in
these contexts.
6.5.2.2p9: A function is called with a prototype in scope that specifies
a type for a parameter that is incompatible with the type declared for
that parameter in the function definition, but they are SRAR types.
In each of these cases, if the ABI used by the implementation calls for
the two SRAR types to be placed in different registers, then the calling
function will place the argument's value in one register, but the
calling function will try to retrieve it from a different register. Such
an ABI would impose severe complications on <stdarg.h> if it applied to
functions with a variable number of arguments, but for calls to other
types of functions it's not particularly odd or hard to implement (it
would be hard to motivate such an ABI feature, but that's not relevant
to my argument).
With such an ABI, the attempt to interchange the types has failed,
because the information was not successfully passed from the calling
function to the called function.
For interchangeability as return types from functions:
6.5.2.2p9: a function is called with a prototype in scope that specifies
a return type that is incompatible with the return type specified in the
function definition, but they are SRAR types.
In this case, if the ABI used by the implementation specifies that the
two SRAR types must be placed in different registers, then the called
function will place it's return value in one register, while the calling
function will attempt to read that value from a different register.
Attempting to interchange the types has failed again, because the
information was not successfully passed from the called function to the
calling function.
For interchangeability of SRAR types as members of unions, I cannot come
up with a good counter-example. This might be because the standard is
right in this case, but it's more likely due to a lack of imagination on
my part.
The standard doesn't define "same" and it wouldn't be the first time
the standard uses a word with a different meaning than the established
one. ...
The rule is that if an alternative definition, provided neither by the
standard itself, nor by ISO/IEC 2382−1 or ISO 31−11, the the meaning
from ordinary English (as used in IT contexts) applies. I don't have
copies of either ISO/IEC 2382−1 or ISO 31−11, so I can't be sure, but I
doubt that either one of them provides a definition of the word "same"
that is sufficiently unconventional as to invalidate SRAR transitivity.
... For example "byte" usually means a quantity of 8 bits but that's
not how the standard defines it. It also uses "overflow" in a
specialised manner ,
In both cases, the standard explicitly provides the alternative
definition that applies when those terms are used in the context of the
standard. The standard provides no alternative definition for "same",
and gives us no reason to suspect that any meaning other than the
conventional English meaning is intended.
If the belief is incorrect then there is a contradiction between the
belief and reality.
Yes, but that's not the contradiction you were describing. You were
describing a non-existent contradiction between SRAR(unsigned char*,
char*) and the fact that they are incompatible types. That incorrect
belief was an essential step in reaching the faulty conclusion that
there was a contradiction between those two facts.
....
If one assumes that "same" has its ordinary English meaning and if one
used formal logic to derive consequences from the standard (which would
be rather hard to do since the standard is not written in a formal
language) and ....
... if one chose a logic which contains the rule that from a
contradiction you can derive anything ...
That's not a special rule for a special kind of logic. It's a fact
derivable from the ordinary rules of conventional logic.
... then one could indeed conclude
that any statement is both true and false. But since people use
informal reasoning to draw conclusions from the standard I don't think
that your excursion into logic is relevant to the discussion.
Reaching a conclusion of "not-A" from an argument whose premises include
"A", is a little too informal for my tastes. Your tastes may differ, in
which case we have nothing useful to discuss.
So the question is , does the assumption that SRAR is transitive
provide guarantees useful for C programming which one wouldn't have
without this assumption ?
I think the derived fact (NOT an assumption) that SRAR is transitive is
precisely as useful as SRAR itself. In a theoretical sense, both are
pretty much useless, without the corresponding guarantee of
interchangeability. In a practical sense, interchangeability of SRAR
types is a reality on most real systems, making SRAR moderately useful,
and the transitivity of SRAR comparably useful.
....
But with such a modification a compiler would not have to warn you if
you did for example strcmp(p1 , p2) and p1 has type unsigned char* .
Don't you think this might create problems ?
No, not really. I would expect that anyone writing such code would
intend to produce precisely the behavior that would be produced by
reason of the newly-guaranteed interchangeability of char* and unsigned
char*. If so, the author would be annoyed, rather than pleased, to
receive such warnings.
... Personally I don't have a
problem with the constraints in this area but I would want at the end
of footnote 39 the addition "provided no compatibility rules are
violated".
Keep in mind that footnotes are non-normative, so placing such a clause
in a footnote would be pointless. Footnotes are supposed to point out
in-obvious facts that can be derived from the facts given in normative
text; footnotes cannot be the source of new facts about C.
Interchangeability was supposedly derivable from "same representation
and alignment"; my objection is not to the interchangeability, but to
the fact that is not in fact derivable from those things.