Quote B {}
Quote A {
}
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.
For types T1 and T2 I define INPL(T1 , T2) ("IN PLace") to mean
that by using the standard and without considering the peculiarities of
any specific implementation you can reach the following conclusion :
for every i>0, for every function foo() which takes at least i
arguments , for every call foo() which has an object of type T2 given
by expression E at position i and the call does not cause undefined
behavior , then by putting at position i "(T1)E" and keeping everything
else the same , the function will operate in precisely the same manner
i.e. return the same value (if it returns a value) , cause the same
side effects etc.
I call T1 and T2 interchangeable (as arguments to functions) if we have
INPL(T1 , T2) and INPL(T2 , T1) .
So for example char* and void* are interchangeable.
In quote A I pointed out that if you have at some point in the code
foo(...,E,...) and futher down foo(...,(T1)E,...) then it may happen
that the object in position i may be passed in register R in the first
call and R' in the second call with R!=R' and the types being
interchangeable or compatible has nothing to do with it. From your
puzzled reaction I take it that when you spoke of "different registers"
you had something else in mind. But despite your long post I still
don't know what nor am I sure what you mean by interchangeable. Before
reading the post I'm replying to I was assuming that you had in mind
more or less the same definition I give above , possibly with less
detail , but now I'm not sure. But never mind. With enough perseverance
we'll manage to understand each other even if it means beaming down on
a planet and fighting a monster.
[...]
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.
And here you lost me. Interchangeability being meaningful has nothing
to do with whether it is implied by SRAR or anything else. If A has a
meaningful definition then A is meaningful. You can't know whether B
implies A without first knowing that A is meaningful. Similarly I can't
imagine what connection can there possibly be between interchangeability
being meaningful and undefined behavior or lack thereof.
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.
If the behavior is undefined then there are no constraints whatsoever
nor are there any expected results. Undefined behavior can turn your
computer into a frog for all you know.
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
I take it that last line should read "called 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.
All this may happen but I still don't see how it justifies your quote
B. Perhaps this particular ABI makes it impossible to write a
conforming C implementation ? And I'm still not clear what scenario
you have in mind. Could you show some C code which may cause all these
things to happen ?
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.
That's ok , for the time being I'm more concerned with understanding
what you mean than covering all cases. If you feel you can illustrate
your point by restricting your attention to arguments to functions
that's fine by me.
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.
I doubt it too.
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.
I commented on that in [1].
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.
It's not clear to me what distinction you're making here. If the
correctness of the belief has to be used in reaching a contradiction
then there's no contradiction "between those two facts" , the
contradiction arises if we assume that a) "Same" in footnote 39 of
6.2.5 p27 has its usual meaning b) The belief expressed in footnote 39
is correct c) unsigned char* and char* are not compatible d) A few
other parts of the standard. That's the contradiction I was describing
in [2] where I used the term "contradiction" and I suggested that we
resolve the contradiction by abandoning the assumption that "SRAR is
transitive" which follows from a).
That's not a special rule for a special kind of logic. It's a fact
derivable from the ordinary rules of conventional logic.
What do you mean by "conventional logic" ? If you mean the logic we use
in everyday life then for the most part it doesn't have formal rules.
On occasion you may hear someone refer to some formal rule but I don't
think that most people would agree that "if the moon is made out of
cheese then 1 equals 2" is a correct implication although it is correct
in some formal logics and in classical logic in particular.
Reaching a conclusion of "not-A" from an argument whose premises include
"A", is a little too informal for my tastes.
That might have been perfectly legitimate depending on what the other
premises were. But in any case I don't recall doing any such thing.
Can you provide a quote ?
Your tastes may differ, in
which case we have nothing useful to discuss.
I think the derived fact (NOT an assumption)
Ok , the assumption that "same" is used with its usual meaning in
footnote 39.
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.
Could you show me some code which you find useful and depends on the
transitivity of SRAR ?
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.
How can you be sure he didn't make a mistake ? Apart from that , does
your idea of interchangeability imply that the assignment from unsigned
char to char , which may happen when strcmp is executing , will always
produce predictable results ?
Keep in mind that footnotes are non-normative, so placing such a clause
in a footnote would be pointless.
It would stop the footnote from being misleading so it wouldn't be
pointless at all.
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.
And the addition I'm suggesting would alert the unwary reader to the
fact that the footnote is not the full story with regards to
interchangeability.
[1] <
[email protected]>
http://groups.google.com/group/comp.lang.c/msg/d444fb5c8d154e4e?dmode=source
[2] <
[email protected]>
http://groups.google.com/group/comp.lang.c/msg/1b34271463a527f6?dmode=source