Topic: reinterpret cast int* to unsigned* (was: Mutable references?)
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 19 Jul 1994 00:57:17 GMT Raw View
In article <CsIGEI.Et3@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
>In article <CsHHqM.G2z@ucc.su.OZ.AU>,
>John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>> Auto and static objects persist. The C Standard defines
>> their lifetimes and it DENIES EXPLICITLY the existence
>> of other objects.
>> *pi is not auto.
>> *pi is not static.
>> Therefore it is not an object. Contradiction.
>
>Have you ever read the Standard, or are you just an illiterate idiot ?
Try reading it yourself. ISO C Standared, 6.1.2.4 Storage
Duration of objects:
"An object has a storage duration that determines its lifetime.
There are two storage durations, static and automatic."
A heap "object" has neither of the allowed storage durations.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 19 Jul 1994 01:27:21 GMT Raw View
In article <CsIHG1.Eyz@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
>In article <CsHH02.EzD@ucc.su.OZ.AU>,
>
>There is no concept of an INSTRINSIC [sic] type in the Standard.
In the C Standard. But in the C++ CD there probably will be.
Its necessary for C++ "polymorphic" objects I think.
>I'll try, just once, to explain what's happening.
I know whats happening. The problem is to _describe_
it precisely and completely and the C Standard does not.
>
...
>This code is illegal, not because the same object is given two types,
>but because the value is being accessed through an lvalue with a
>different type.
With a different type to WHAT??
Thats the problem -- the C Standard is plain when one of the
type is declared. But its nonsense to talk about accessing
"an object" with different types. The object refered to ALWAYS
has the type of the lvalue used to denote it. And generally,
since an lvalue is an expression, and an expression is something
that is executed, there cannot be a situation (usually -- give
of take a few sequence points) in which there exists more than
one lvalue denoting an object at any one time.
>Note that the following code is perfectly legal:
>
> void f() {
> int *pi = malloc(sizeof(float)+sizeof(int));
> float * pf;
> *pi = 1;
> pf = (float*)(void*)pi;
> *pf = 1;
> printf("%f", *pf);
> }
>
>The malloced object is still given two types, but every time its value
>is examined, it is done so through the type it was stored with.
Exactly. So the "real" type of the object is determined
by storing a value -- exactly as I claim.
>
>> I dont see that the aliasing
>> rules exclude this code, since while *pi is an alias
>> for *pf, neither is a declared variable, and the aliasing
>> rules only apply to _declared_ variables.
>
>Where on earth did you get that stupid idea. The aliasing rules apply to
>*objects*. *READ* subclause 6.3, don't reinvent it.
Read it yourself. 4 of the aliasing rules refer to
the "declared type of an object". After all, objects
dont have an intrinsic type in ISO C, so one must somehow
give them one which persists -- which is why there is a
reference to the declaration, which attributes both
a type and a lifetime to a region of store.
>> Now, MY rules make this second example illegal because a float lvalue
>> may NOT be used to access an int object, and the object
>> HAS the type int BECAUSE an int value was stored there.
>
>We're not playing by your rules.
>Thankfully.
>
If you write C++ you probably will be :-)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 19 Jul 1994 01:39:24 GMT Raw View
In article <CsIHun.F2p@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
>In article <CsIGEI.Et3@scone.london.sco.com>,
>Clive D.W. Feather <clive@sco.com> wrote:
>>In article <CsHHqM.G2z@ucc.su.OZ.AU>,
>>John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>> Have you ever read the Standard, or are you just an illiterate idiot ?
>> Subclause 7.10.3.3:
>> || The /malloc/ function allocates space for an object whose size is
>> || specified by /size/ and whose value is indeterminate.
>
>On second thoughts, I retract the term "idiot" and apologise for it.
Accepted.
>I've just looked at 6.1.2.4, and it does indeed say:
>
>|| An object has a *storage duration* that determines its lifetime.
>|| There are two storage durations, static and automatic.
>
>This is a Defect.
It seems to be.
>There are *three* storage durations [1]: static, automatic,
>and heap. Malloced objects have heap storage duration. A Defect Report
>will be submitted.
Its not that simple, I suspect. What is a malloced object?
A char array of size n? What has this to do with the use of that
array to store quite different entities like a float?
Read again the
aliasing rules and note that auto and static objects
"effectively" have an instrinsic type _because_ they
are declared -- they have the type and lifetime determined
by the declaration. That cant work for objects stored
in malloced store. Nor, for that matter, can it work for
objects stored in an auto or static buffer.
>
>Moral: when making assertions like "DENIES EXPLICITLY", give references
>so that we can see what you are talking about.
Sorry, I didnt have the ISO C Standard handy at the time
(having just moved house everything is hiding :-)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: miket@world.std.com (Michael Trachtman)
Date: Tue, 19 Jul 1994 03:57:47 GMT Raw View
In an article, John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: In article <CsIHun.F2p@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
: >In article <CsIGEI.Et3@scone.london.sco.com>,
: >Clive D.W. Feather <clive@sco.com> wrote:
: >> Have you ever read the Standard, or are you just an illiterate idiot ?
: >> Subclause 7.10.3.3:
: >
: >On second thoughts, I retract the term "idiot" and apologise for it.
: Accepted.
That still leaves: "or are you just an illiterate ?".
That should be retracted too and apologized for....
Michael T.
Author: clive@sco.com (Clive D.W. Feather)
Date: Tue, 19 Jul 1994 13:27:29 GMT Raw View
In article <Ct5z9p.CnF@ucc.su.OZ.AU>,
John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>> There are *three* storage durations [1]: static, automatic,
>> and heap. Malloced objects have heap storage duration.
> Its not that simple, I suspect. What is a malloced object?
> A char array of size n? What has this to do with the use of that
> array to store quite different entities like a float?
Wrong. A malloced object is an object: a region of data storage. Note
the wording of 3.14: "When referenced, an object may be interpreted as
having a particular type;". A malloced object is not "a char array of
size n" but is a region of n bytes.
> Read again the
> aliasing rules and note that auto and static objects
> "effectively" have an instrinsic type _because_ they
> are declared -- they have the type and lifetime determined
> by the declaration. That cant work for objects stored
> in malloced store.
Hmm, I'll have to think on that.
> Nor, for that matter, can it work for
> objects stored in an auto or static buffer.
I don't know what this means.
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: clive@sco.com (Clive D.W. Feather)
Date: Tue, 19 Jul 1994 13:41:20 GMT Raw View
In article <Ct5ypL.B2D@ucc.su.OZ.AU>,
John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>In article <CsIHG1.Eyz@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
>> There is no concept of an INSTRINSIC [sic] type in the Standard.
> In the C Standard. But in the C++ CD there probably will be.
The more I hear about the C++ CD, the more I'm glad I don't use C++.
>> This code is illegal, not because the same object is given two types,
>> but because the value is being accessed through an lvalue with a
>> different type.
> With a different type to WHAT??
To the one that was used to store the value.
> Thats the problem -- the C Standard is plain when one of the
> type is declared. But its nonsense to talk about accessing
> "an object" with different types. The object refered to ALWAYS
> has the type of the lvalue used to denote it.
No it isn't. In:
int i;
i = 1;
* (char *) &i = 2;
the same object (designated by "i") is accessed with two different types.
3.14 is clear that it is the same object.
>> Note that the following code is perfectly legal:
[...]
>> The malloced object is still given two types, but every time its value
>> is examined, it is done so through the type it was stored with.
> Exactly. So the "real" type of the object is determined
> by storing a value -- exactly as I claim.
NO NO NO. The object doesn't have a "real" type. At *each* point of
access, the object is *interpreted* as having a specific type. See 3.14.
[6.3]
> Read it yourself. 4 of the aliasing rules refer to
> the "declared type of an object".
This has been asked in Defect Report 28. The answer states that the
intent of this list is to allow a compiler to determine when aliasing
might occur, and these rules apply to malloced objects as well. I
interpret this to mean that the "declared type" is that of the lvalue
used to access the object; a compiler may assume that, once the object
has been accessed through one lvalue, it can then only be accessed via
lvalues matching those rules.
> After all, objects
> dont have an intrinsic type in ISO C, so one must somehow
> give them one which persists
Why ?
>>> Now, MY rules make this second example illegal because a float lvalue
>>> may NOT be used to access an int object, and the object
>>> HAS the type int BECAUSE an int value was stored there.
>> We're not playing by your rules.
>> Thankfully.
> If you write C++ you probably will be :-)
I don't. Thankfully.
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sat, 23 Jul 1994 09:51:39 GMT Raw View
In article <Ct6w1u.EFA@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
>In article <Ct5z9p.CnF@ucc.su.OZ.AU>,
>John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>>> There are *three* storage durations [1]: static, automatic,
>>> and heap. Malloced objects have heap storage duration.
>> Its not that simple, I suspect. What is a malloced object?
>> A char array of size n? What has this to do with the use of that
>> array to store quite different entities like a float?
>
>Wrong. A malloced object is an object: a region of data storage. Note
>the wording of 3.14: "When referenced, an object may be interpreted as
>having a particular type;". A malloced object is not "a char array of
>size n" but is a region of n bytes.
Yes. You are correct. In C, any contiguous extent of
storage may be called an object. An object has no "type".
However, when an extent of store is refered to by an lvalue,
one may speak of the "type of the object" meaning
"the unqualified type of the lvalue denoting that extent
of store." Have I got this right now?
>
>> Read again the
>> aliasing rules and note that auto and static objects
>> "effectively" have an instrinsic type _because_ they
>> are declared -- they have the type and lifetime determined
>> by the declaration. That cant work for objects stored
>> in malloced store.
>
>Hmm, I'll have to think on that.
>
>> Nor, for that matter, can it work for
>> objects stored in an auto or static buffer.
>
>I don't know what this means.
Let me try to explain with an example.
Suppose I have declared a long int somewhere and try
to read-access it as a float (by punning, unions, or whatever).
Now, either such an access is well defined, in which case
the Standard (be it C or C++) must say what happens, or it is
not well defined -- in which case the Standard must discriminate
which acessess are valid and which ones are not. After all
_some_ accesses are valid, for example accessing a declared
and initialised float with a float lvalue is valid and had better
yield the last float value stored in the object denoted
by (both) the declaration and the lvalue.
So: the problem is "how to word the Standard to guarrantee
that certain accesses to objects are well defined, and to define
the behaviour in those cases, and to say which accesses these are".
Here's an example of what might be a valid access:
if a variable is declared and initialised then its stored
value may be read using an lvalue of the same type which
denotes the same object as the use of the name of the
variable in an expression would.
I hope you agree such an access is valid,
and my description is vaguely comprehensible.
The question is: what other accesses are valid?
I believe that if I have a char buffer and use an lvalue
to store a value into it, then the Standard should
guarrantee I can use another lvalue of the same type
denoting the same object to retrieve that value
(provided the store is not scrambled in the meantime;
some such scramblings may be valid, some may not be)
It is not clear that the C Standard provides
this guarrantee, or prohibits accesses for which
it does not provide semantics. I dont actually care
what the C Standard says, what I want to do is to find
suitable words that _do_ provide the appropriate
assurances and restrictions for C++ -- naturally it would be
wise to use the "best" of the ISO C Standard,
and to provide "better" where it is defective (if anywhere).
Let me give you a _complicated_ example.
Suppose one examines "UINT_MAX" and "CHAR_BIT" and
"sizeof(unsigned)" and discovers that all the bits
of the store of an unsigned are significant.
Now, we dont know from this whether the
representation is big endian, or little endian,
or there is some weird order of bits -- but
WE CAN FIND OUT. We can in this case determine
exactly what the representation is.
The question is now whether having done so
we're entitled to access the store of an int with an
array of unsigned char, fiddle with the bits,
then load the unsigned integer value, knowing
exactly what it will be.
(I've actually DONE this, so the question is not rhetorical)
Note that whatever explanation we give, in C
its going to be tricky because we cant say 'you may not
access a "long int" object with a "float" lvalue'.
Because, there are no "long int" objects, as you pointed out,
in C an object is just a sequence of bytes. Thus valid
accesses must be determined somehow by the "history"
of accesses to those bytes, or, the existence of
some other entity which denotes those bytes -- such as a declared
variable (or something else I haven't thought of :-)
The bytes themselves have no properties which can be
used to permit or exclude accesses (other than their address and length).
I think that is very hard. Which is why I propose
instead to determine that in C++ objects _do_ have an
instrinsic type. Then you can say "you may not access a long
int object with a float lvalue". The problem of how a particular
type is associated with the storage extent remains.
This approach is more or less mandatory in C++ for
encapsulated objects of class type anyhow -- otherwise
how do we explain polymorphism? That is, I believe that
the notion that an object "has a type" is the common
understanding in object oriented languages.
It is exactly this difference of viewpoint between
C (which is not object oriented) and C++ (which is), that
makes describing the C++ object model so difficult:
I would like to see a single coherent notion of object.
Given that the ISO C notion of object
a) may be faulty
b) doesnt work well for class types anyhow
it seems reasonable to persue the approach that objects have
an intrinsic type and see if this will not only explain
C behaviour, but perhaps explain it _better_ than the ISO C Standard.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sat, 23 Jul 1994 10:08:33 GMT Raw View
In article <Ct6woy.EIK@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
>In article <Ct5ypL.B2D@ucc.su.OZ.AU>,
>John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>>In article <CsIHG1.Eyz@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
>>> There is no concept of an INSTRINSIC [sic] type in the Standard.
>> In the C Standard. But in the C++ CD there probably will be.
>
>The more I hear about the C++ CD, the more I'm glad I don't use C++.
I have some sympathy for that view :-)
>
>>> This code is illegal, not because the same object is given two types,
>>> but because the value is being accessed through an lvalue with a
>>> different type.
>> With a different type to WHAT??
>
>To the one that was used to store the value.
Aha! Thats what I thought. In what way is there
any difference between
"the type of the lvalue used to store a value in an object"
and
"the type of the object"
if I simply _define_ the type of the object as that of the
lvalue used to store a value into an extent of store?
[By the way, I believe your answer is not ISO C. That is,
its just as invalid to access a declared float as an int
_even if no float value has been stored_. Indeed,
it is exactly this reliance on the declaration that allocates
the store and NOT on the last stored value that I have problems
with. I _agree_ with your interpretation, but it isnt ISO C,
unless I'm gravely mistaken. The way I see it, storing
a value _creates_ an object of the type of the value,
and that is equivalent to your statement although the meaning
of "object" differs]
>
>> Thats the problem -- the C Standard is plain when one of the
>> type is declared. But its nonsense to talk about accessing
>> "an object" with different types. The object refered to ALWAYS
>> has the type of the lvalue used to denote it.
>
>No it isn't. In:
>
> int i;
>
> i = 1;
> * (char *) &i = 2;
>
>the same object (designated by "i") is accessed with two different types.
>3.14 is clear that it is the same object.
It must be severely confused. I thought you said
an object was an extent of n bytes? Didnt you?
Well, on most systems sizeof(char) != sizeof(int)
and so the extents of store are not equal and so it CANNOT
possibly be the same object that is denoted.
It is true the extents of store overlap. But so what?
Where are the rules about overlapping objects?
>
>> After all, objects
>> dont have an intrinsic type in ISO C, so one must somehow
>> give them one which persists
>
>Why ?
So you can tell if an access to an object is well defined
or not.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: baynes@ukpsshp1.serigate.philips.nl (Stephen Baynes)
Date: Mon, 25 Jul 1994 07:15:18 GMT Raw View
John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: In article <Ct6w1u.EFA@scone.london.sco.com> clive@sco.com (Clive D.W. Feather) writes:
-snip-
: Let me try to explain with an example.
: Suppose I have declared a long int somewhere and try
: to read-access it as a float (by punning, unions, or whatever).
: Now, either such an access is well defined, in which case
: the Standard (be it C or C++) must say what happens, or it is
: not well defined -- in which case the Standard must discriminate
: which acessess are valid and which ones are not. After all
: _some_ accesses are valid, for example accessing a declared
: and initialised float with a float lvalue is valid and had better
: yield the last float value stored in the object denoted
: by (both) the declaration and the lvalue.
: So: the problem is "how to word the Standard to guarrantee
: that certain accesses to objects are well defined, and to define
: the behaviour in those cases, and to say which accesses these are".
: Here's an example of what might be a valid access:
: if a variable is declared and initialised then its stored
: value may be read using an lvalue of the same type which
: denotes the same object as the use of the name of the
: variable in an expression would.
: I hope you agree such an access is valid,
: and my description is vaguely comprehensible.
: The question is: what other accesses are valid?
: I believe that if I have a char buffer and use an lvalue
: to store a value into it, then the Standard should
: guarrantee I can use another lvalue of the same type
: denoting the same object to retrieve that value
: (provided the store is not scrambled in the meantime;
: some such scramblings may be valid, some may not be)
: It is not clear that the C Standard provides
: this guarrantee, or prohibits accesses for which
: it does not provide semantics. I dont actually care
: what the C Standard says, what I want to do is to find
: suitable words that _do_ provide the appropriate
: assurances and restrictions for C++ -- naturally it would be
: wise to use the "best" of the ISO C Standard,
: and to provide "better" where it is defective (if anywhere).
: Let me give you a _complicated_ example.
: Suppose one examines "UINT_MAX" and "CHAR_BIT" and
: "sizeof(unsigned)" and discovers that all the bits
: of the store of an unsigned are significant.
: Now, we dont know from this whether the
: representation is big endian, or little endian,
: or there is some weird order of bits -- but
: WE CAN FIND OUT. We can in this case determine
: exactly what the representation is.
: The question is now whether having done so
: we're entitled to access the store of an int with an
: array of unsigned char, fiddle with the bits,
: then load the unsigned integer value, knowing
: exactly what it will be.
-snip-
IMHO the only case where it is reasonable and needed in a portable program to
permit access to data other than by the means that it was last written is to
treat it as an array of bytes (signed or unsinged char), to copy those bytes
to another array of bytes in the same order, then this array can be used as an
object of same type as the original object. As far as I can make out the
standard guarrentees this as integral types, which include char, must use all
the bits of the char in a binary encoding which ensures that copying the char
copies all the bits and that any bit pattern is a valid char so that no bit
pattern can cause undefined behaviour.
--
Stephen Baynes baynes@mulsoc2.serigate.philips.nl
Philips Semicondutors Ltd
Southampton My views are my own.
United Kingdom
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Mon, 25 Jul 1994 16:32:34 GMT Raw View
In article <CtHItI.EBx@ukpsshp1.serigate.philips.nl> baynes@ukpsshp1.serigate.philips.nl (Stephen Baynes) writes:
>IMHO the only case where it is reasonable and needed in a portable program to
>permit access to data other than by the means that it was last written is to
>treat it as an array of bytes (signed or unsinged char), to copy those bytes
>to another array of bytes in the same order, then this array can be used as an
>object of same type as the original object. As far as I can make out the
>standard guarrentees this as integral types, which include char, must use all
>the bits of the char in a binary encoding which ensures that copying the char
>copies all the bits and that any bit pattern is a valid char so that no bit
>pattern can cause undefined behaviour.
A recent response by the C committee to Defect Report #69
indicates otherwise :-(
In particular, integral type may have "holes", that is
bits which dont participate in representing the value. If thats
true of the char type memory CANNOT be copied using a char array.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 9 Jul 1994 08:26:36 GMT Raw View
In article <2vj3kg$avr@lucy.ee.und.ac.za> barrett@lucy.ee.und.ac.za (Alan Barrett) writes:
>In article <rfgCsM1I7.D6H@netcom.com>,
>rfg@netcom.com (Ronald F. Guilmette) writes:
>> Second let me just reestablish the context of this discussion. The
>> question at issue was the meaningfulness (or lack thereof) of the
>> conversion of a NEGATIVE value from type `int' to type `unsigned int'.
>
>I thought that the issue was the meaningfulness (or lack thereof)
>of the use of techniques commonly referred to as "type punning" to
>reinterpret a negative-valued integer as if it were an unsigned integer.
>I believe that type punning is not a "conversion" in the sense of
>ANSI/ISO 9899-1990 section 6.2.
>
>> You seem to be claiming that the ISO C standard makes some guarrantees
>> with respect to the value yielded by such a conversion. I claim that
>> there are no such guarrantees offered WITHIN the ISO C standard.
>
>I believe that the second paragraph of section 6.2.1.2 makes some very
>clear guarantees about the behaviour of a *conversion* from a negative
>signed integer to an unsigned integer, and that those guarantees accord
>with what Andrew Koenig said about arithmetic modulo 2**n.
I believe that you are wrong. There are two sentences in that paragraph,
each of which has preconditions. If you look carefully, neither set of
preconditions is satisfied by a NEGATIVE value being converted from a
signed integral type to an unsigned integral type OF THE SAME SIZE.
Thus neither sentence applies to the case under discussion.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: ark@tempel.research.att.com (Andrew Koenig)
Date: Sat, 9 Jul 1994 19:17:09 GMT Raw View
In article <rfgCsM1I7.D6H@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
> Second let me just reestablish the context of this discussion. The
> question at issue was the meaningfulness (or lack thereof) of the
> conversion of a NEGATIVE value from type `int' to type `unsigned int'.
> You seem to be claiming that the ISO C standard makes some guarrantees
> with respect to the value yielded by such a conversion. I claim that
> there are no such guarrantees offered WITHIN the ISO C standard.
> People who actually HAVE a copy of the C standard (including most readers
> of comp.std.c) can judge for themselves which one of us knows whereof he
> speaks. The relevant section would seem to be 6.2.1.2 in the ISO C
> standard (aka 3.2.1.2 in the ``classic'' ANSI C standard).
People who don't have their own copy might find relevant the
following quote from the ANSI C standard:
When a value with integral type is converted to
another integral type, if the value can be
represented by the new type, its value is
unchanged.
When a signed integer is converted to an unsigned
integer with equal or greater size, if the value
of the signed integer is nonnegative, its value
is unchanged. Otherwise: if the unsigned
integer has greater size, the signed integer is
first promoted to the signed integer
corresponding to the unsigned integer; the value
is converted to unsigned by adding to it one
greater than the largest number that can be
represented in the unsigned integer type.
Now, I will admit that I don't have a copy of the ISO C standard
handy. I'm willing to bet, though, that the corresponding statement
there is no different from the excerpt cited above.
What this excerpt says about conversion from `int' to `unsigned int'
is this:
1. If the int is nonnegative, the result is the
the unsigned int with the same value.
2. Otherwise, the part about `if the unsigned
integer has greater size' is irrelevant because
`int' and `unsigned int' have the same size, so
the int is converted to unsigned by adding one more
than the largest unsigned int.
So conversion from int to unsigned int is modulo 2^n, where
n is the number of bits in an unsigned int. Just as I said.
--
--Andrew Koenig
ark@research.att.com
Author: msb@sq.sq.com (Mark Brader)
Date: Sun, 10 Jul 94 04:44:46 GMT Raw View
Note that this is no longer about int * and unsigned int *, but about int
and unsigned int. Also, I am commenting only on ANSI C, not C++.
Alan Barrett (barrett@lucy.ee.und.ac.za) writes:
> > I believe that the second paragraph of section 6.2.1.2 makes some very
> > clear guarantees about the behaviour of a *conversion* from a negative
> > signed integer to an unsigned integer, and that those guarantees accord
> > with what Andrew Koenig said about arithmetic modulo 2**n.
Ronald F. Guilmette (rfg@netcom.com) responds:
> I believe that you are wrong. There are two sentences in that paragraph,
> each of which has preconditions. If you look carefully, neither set of
> preconditions is satisfied by a NEGATIVE value being converted from a
> signed integral type to an unsigned integral type OF THE SAME SIZE.
> Thus neither sentence applies to the case under discussion.
Okay, we need to quote the text in question. It reads:
# When a signed integer is converted to an unsigned integer with equal
# or greater size, if the value of the signed integer is nonnegative,
# its value is unchanged. Otherwise: if the unsigned integer has
# greater size, the signed integer is first promoted to the signed
# integer corresponding to the unsigned integer; the value is converted
# to unsigned by adding to it one greater than the largest number that
# can be represented in the unsigned integer type.
Note the unusual punctuation in the second sentence. The precondition
on that sentence is simply the word "Otherwise"; the if-clause following
it applies only to the wording up to the semicolon. If that wasn't the
intended meaning, they wouldn't have punctuated it that way. In other
words, the paragraph is to be parsed as follows:
When (a signed integer is converted to an unsigned integer
with equal or greater size) {
if (the value of the signed integer is nonnegative) {
its value is unchanged.
} Otherwise {
if (the unsigned integer has greater size) {
the signed integer is first promoted
to the signed integer corresponding
to the unsigned integer;
}
the value is converted to unsigned by adding to
it one greater than the largest number that
can be represented in the unsigned integer type.
}
}
Presumably Ron failed to follow this intended parsing, and misunderstood
the paragraph. Alan is right; the conversion of int to unsigned int is
well defined in ANSI C. And that's why my signature quote works.
--
Mark Brader, msb@sq.com, SoftQuad Inc., Toronto
#define MSB(type) (~(((unsigned type)-1)>>1))
This article is in the public domain.
Author: alan@sal.wisc.edu (Alan Watson)
Date: Sun, 10 Jul 1994 05:07:37 GMT Raw View
In article <rfgCsnzGD.3DL@netcom.com>
rfg@netcom.com (Ronald F. Guilmette) wrote:
>I believe that you are wrong. There are two sentences in that paragraph,
>each of which has preconditions. If you look carefully, neither set of
>preconditions is satisfied by a NEGATIVE value being converted from a
>signed integral type to an unsigned integral type OF THE SAME SIZE.
>
>Thus neither sentence applies to the case under discussion.
I disagree. The paragraph under consideration is (courtesy of Andrew
Koenig):
When a signed integer is converted to an unsigned integer with equal
or greater size, if the value of the signed integer is nonnegative,
its value is unchanged. Otherwise: if the unsigned integer has
greater size, the signed integer is first promoted to the signed
integer corresponding to the unsigned integer; the value is
converted to unsigned by adding to it one greater than the largest
number that can be represented in the unsigned integer type.
It seems clear to me from consideration of the relative grammatical
weights of commas (loosely, used to join clauses) and semicolons
(loosely, used to join what could otherwise be written as separate
sentences), that the relationships between qualifiers and actions in
this paragraph can be written in a somewhat more artificial manner as:
IF the value of the signed integer is nonnegative THEN
its value is unchanged
OTHERWISE
IF the unsigned integer has greater size THEN
the signed integer is first promoted to the signed integer
corresponding to the unsigned integer
ENDIF
the value is converted to unsigned by adding to it one
greater than the largest number that can be
represented in the unsigned integer type
ENDIF
Of course, a definitive comment on English grammar will have to come
from someone for whom English is not a native tongue. (This is your
cue, Jutta.)
--
Alan Watson | And all our yesterdays have lighted fools
alan@oldp.astro.wisc.edu | The way to dusty decks.
Department of Astronomy | -- gnohmon@ssiny.UUCP after Macbeth
University of Wisconsin -- Madison |
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Fri, 1 Jul 1994 19:10:04 GMT Raw View
In article <Cs7rv2.KLv@scone.london.sco.com> clive@scone.london.sco.com (Clive D.W. Feather) writes:
>>> Bill says the same applies to int* and unsigned* -- I cant
>>> understand exactly why, or how two pointers to the SAME
>>> object type could have distinct representations
>
>In ISO C, int and unsigned are different types (though values that are
>in the range of both types have the same representation in both).
>Therefore (int *) and (unsigned *) are different types.
>
>The term you need to look for is "compatible type".
>
>Pointers to compatible types with the same qualification are compatible,
>so (int *) is compatible with (int *), but not with (unsigned *) or
>(int * const).
No, I'm not interested in compatible types here,
but types with the "same representations", that is, the same
object layouts with the same alignment requirements and size
(and a few other things). The meaning
of "same representation" is that you can sensibly alias
the object as one type or the other and access it through
either alias. For example:
int x;
int *px = &x;
unsigned * py = (unsigned*)px;
py = 1;
assert(py==px);
I speak of the common type which the object must have to allow
this as the "type of the object". I propose in C++ this
is an intrinsic property of the object and is NOT determined
"by the lvalue than access it" as it is in C -- because the
C Standard is broken exactly because it uses that definition.
Change the example above to use "malloc" to see why.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 2 Jul 1994 02:13:02 GMT Raw View
In article <Cs9zwt.H6w@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
> No, I'm not interested in compatible types here,
>but types with the "same representations", that is, the same
>object layouts with the same alignment requirements and size
>(and a few other things). The meaning
>of "same representation" is that you can sensibly alias
>the object as one type or the other and access it through
>either alias. For example:
Honestly. Get a grip John. Types that are different are DIFFERENT.
You cannot just casually play games (either with unions or with
bogus pointer conversions) and expect the results to be correct
afterwards. If I store a -3 int a type `signed int' variable,
and they cleverly manage to get that interpreted as a `unsigned int'
the result will not be `sensible' in any sense.
So please stop talking about ``sensibly'' aliasing an object of one
as an object of a different type... at least until you have *thought*
about what you are saying.
> int x;
> int *px = &x;
> unsigned * py = (unsigned*)px;
> py = 1;
> assert(py==px);
>
>I speak of the common type which the object must have to allow
>this as the "type of the object". I propose in C++ this
>is an intrinsic property of the object and is NOT determined
>"by the lvalue than access it" as it is in C -- because the
>C Standard is broken exactly because it uses that definition.
The C standard is not broken. It is your understanding which is
broken. I proposed that you fix *that* before casting any more
aspersions in the direction of something which is, after all, a
rather well written standard.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 3 Jul 1994 16:02:14 GMT Raw View
In article <rfgCsAJHq.2Is@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <Cs9zwt.H6w@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>>
>> No, I'm not interested in compatible types here,
>>but types with the "same representations", that is, the same
>>object layouts with the same alignment requirements and size
>>(and a few other things). The meaning
>>of "same representation" is that you can sensibly alias
>>the object as one type or the other and access it through
>>either alias. For example:
>
>Honestly. Get a grip John. Types that are different are DIFFERENT.
>You cannot just casually play games (either with unions or with
>bogus pointer conversions) and expect the results to be correct
>afterwards. If I store a -3 int a type `signed int' variable,
>and they cleverly manage to get that interpreted as a `unsigned int'
>the result will not be `sensible' in any sense.
You are wrong. The rules are that if the value of
an int or signed int is in the intersection of the set of
values representable by both, then a reinterpretation via
a union or cast is REQUIRED to yield the same value.
>>I propose in C++ this
>>is an intrinsic property of the object and is NOT determined
>>"by the lvalue than access it" as it is in C -- because the
>>C Standard is broken exactly because it uses that definition.
>
>The C standard is not broken. It is your understanding which is
>broken. I proposed that you fix *that* before casting any more
>aspersions in the direction of something which is, after all, a
>rather well written standard.
I'm sorry that you do not understand my explanation
of the problem. Please try.
void f() {
int *pi = malloc(sizeof(int));
*pi = 1;
printf("%d", *pi);
}
Nothing in the C Standard promises that the output will be "1".
As far as I know. Please point out the words that contradict
this assertion if you can, thus educating me.
But everyone knows the output must be 1, and such a promise is NECESSARY
for almost all C programs to work.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 4 Jul 1994 00:55:00 GMT Raw View
In article <CsDGJr.376@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>In article <rfgCsAJHq.2Is@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>>In article <Cs9zwt.H6w@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>>>
>>> No, I'm not interested in compatible types here,
>>>but types with the "same representations", that is, the same
>>>object layouts with the same alignment requirements and size
>>>(and a few other things). The meaning
>>>of "same representation" is that you can sensibly alias
>>>the object as one type or the other and access it through
>>>either alias. For example:
>>
>>Honestly. Get a grip John. Types that are different are DIFFERENT.
>>You cannot just casually play games (either with unions or with
>>bogus pointer conversions) and expect the results to be correct
>>afterwards. If I store a -3 int a type `signed int' variable,
>>and they cleverly manage to get that interpreted as a `unsigned int'
>>the result will not be `sensible' in any sense.
>
> You are wrong. The rules are that if the value of
^^^^^^^^^^^^
>an int or signed int is in the intersection of the set of
>values representable by both, then a reinterpretation via
>a union or cast is REQUIRED to yield the same value.
My point remains that this is only true IN SOME CASES. As far as general
rules go, all one can say is that pretending a `signed int' is in fact an
`unsigned int' can lead to trouble (and probably should be discouraged...
just as the C standard already attempts to do).
> I'm sorry that you do not understand my explanation
>of the problem. Please try.
>
> void f() {
> int *pi = malloc(sizeof(int));
> *pi = 1;
> printf("%d", *pi);
> }
>
>Nothing in the C Standard promises that the output will be "1".
>As far as I know. Please point out the words that contradict
>this assertion if you can, thus educating me.
Space is allocated sufficient to hold an int. You put a 1 into that space
and you get a 1 out. What's your question?
(I might point out that nothing in the standard guarrantees that the sum
of the angles of a triangle add up to 180 degrees, or that parallel lines
don't intersect, but then all documents such as this rely on at least
*some* fundamental assumptions about the nature of reality. If they didn't,
they`d all be 50 feet thick, weight in at 500 pounds, and be authored by
Bertrand Russell.)
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 4 Jul 1994 08:19:11 GMT Raw View
rfg@netcom.com (Ronald F. Guilmette) writes:
>As far as general
>rules go, all one can say is that pretending a `signed int' is in fact an
>`unsigned int' can lead to trouble (and probably should be discouraged...
>just as the C standard already attempts to do).
Well, since it does define the behaviour in some of these
int/unsigned cases, I wouldn't call it strong discouragement.
However, the C standard apparently doesn't define the behaviour at all if
you pretend that a `signed int *' is in fact an `unsigned int *',
e.g.
#include <stdio.h>
int main() {
int x = 1;
int *i;
*(unsigned **)&i = (unsigned *) &x;
printf("%d", *i);
return 0;
}
Now would it really be a burden on implementors if C++ allowed
programmers to do this? I'm not saying that this would necessarily be
a good idea, but I imagine that it works with all existing
implementations, since I expect that they all use the same
representation for `int *' as they use for `unsigned *'. Please
correct me if I'm wrong and there really is some reason why
implementations might want to represent these types differently.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: diamond@jrd.dec.com (Norman Diamond)
Date: 5 Jul 1994 01:26:34 GMT Raw View
In article <9418518.3625@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>rfg@netcom.com (Ronald F. Guilmette) writes:
>>As far as general rules go, all one can say is that pretending a
>>`signed int' is in fact an `unsigned int' can lead to trouble (and probably
>>should be discouraged... just as the C standard already attempts to do).
>Well, since it does define the behaviour in some of these
>int/unsigned cases, I wouldn't call it strong discouragement.
>However, the C standard apparently doesn't define the behaviour at all if
>you pretend that a `signed int *' is in fact an `unsigned int *',
That is indeed true, ANSI Classic section 3.3, page 39 lines 22 to 24,
allow accesses to integral objects via lvalues that differ in signedness
and/or have more qualifications than the actual objects, but do not make
related allowances for pointers to integral objects.
However, even though the access is allowed, it is not entirely clear if
the resulting value makes any sense. For values in the intersection of
the signed and unsigned types, probably yes. For other values, for most
practical purposes yes (though the effect depends on one's vs two's
complement etc.) but for the purposes of the standard it is not clear.
For comparison, line 27 allows access via a character type, but there is
no guarantee that the resulting value will make any sense at all. If you
modify a float by storing into each of its characters, then even for
practical purposes the result is often undefined.
I do not know how much of this will change as the result of a technical
corrigendum.
>Now would it really be a burden on implementors if C++ allowed
>programmers to do this?
If the hardware has tag bits describing characteristics of an object,
then C already forces implementors to evade the tags for signed vs
unsigned types. If the hardware has tag bits in pointers describing
pointed-to objects, then C does not force similar evasion, but I think
it would not increase the degree of nuisance if C did force it. I think
that implementors would not be further burdened if C++ did both of these.
--
<< If this were the company's opinion, I would not be allowed to post it. >>
A program in conformance will not tend to stay in conformance, because even if
it doesn't change, the standard will. Force = program size * destruction.
Every technical corrigendum is met by an equally troublesome new defect report.
Author: volpe@bart.crd.ge.com (Christopher R. Volpe)
Date: Tue, 5 Jul 1994 13:48:39 GMT Raw View
In article <CsDGJr.376@ucc.su.OZ.AU>, maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>In article <rfgCsAJHq.2Is@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>>In article <Cs9zwt.H6w@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>>>
>>> No, I'm not interested in compatible types here,
>>>but types with the "same representations", that is, the same
>>>object layouts with the same alignment requirements and size
>>>(and a few other things). The meaning
>>>of "same representation" is that you can sensibly alias
>>>the object as one type or the other and access it through
>>>either alias. For example:
>>
>>Honestly. Get a grip John. Types that are different are DIFFERENT.
>>You cannot just casually play games (either with unions or with
>>bogus pointer conversions) and expect the results to be correct
>>afterwards. If I store a -3 int a type `signed int' variable,
>>and they cleverly manage to get that interpreted as a `unsigned int'
>>the result will not be `sensible' in any sense.
>
> You are wrong. The rules are that if the value of
>an int or signed int is in the intersection of the set of
>values representable by both, then a reinterpretation via
>a union or cast is REQUIRED to yield the same value.
That's not what he said, John. "-3" is not in the intersection of values
representable by both int and unsigned int.
>
>>>I propose in C++ this
>>>is an intrinsic property of the object and is NOT determined
>>>"by the lvalue than access it" as it is in C -- because the
>>>C Standard is broken exactly because it uses that definition.
>>
>>The C standard is not broken. It is your understanding which is
>>broken. I proposed that you fix *that* before casting any more
>>aspersions in the direction of something which is, after all, a
>>rather well written standard.
>
> I'm sorry that you do not understand my explanation
>of the problem. Please try.
>
> void f() {
> int *pi = malloc(sizeof(int));
> *pi = 1;
> printf("%d", *pi);
> }
>
>Nothing in the C Standard promises that the output will be "1".
>As far as I know. Please point out the words that contradict
>this assertion if you can, thus educating me.
The entire standard, taken as a whole, promises this. "*pi" is an int.
It has the value "1". The semantics of malloc, pointers, simple assignment,
and printf guarantee that the output is 1. Where do you think the
alleged ambiguity of this program comes from?
>
>But everyone knows the output must be 1, and such a promise is NECESSARY
>for almost all C programs to work.
>--
> JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
> Maxtal Pty Ltd, CSERVE:10236.1703
> 6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
> NSW 2131, AUSTRALIA
--
Chris Volpe Phone: (518) 387-7766 (Dial Comm 8*833
GE Corporate R&D Fax: (518) 387-6560
PO Box 8, Schenectady, NY 12301 Email: volpecr@crd.ge.com
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 5 Jul 1994 20:02:26 GMT Raw View
In article <rfgCsE57o.4tx@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>>
>> void f() {
>> int *pi = malloc(sizeof(int));
>> *pi = 1;
>> printf("%d", *pi);
>> }
>>
>>Nothing in the C Standard promises that the output will be "1".
>>As far as I know. Please point out the words that contradict
>>this assertion if you can, thus educating me.
>
>Space is allocated sufficient to hold an int. You put a 1 into that space
>and you get a 1 out. What's your question?
Which rule ensures this? I agree with your explanation.
But what you have said must be codified in the Standard. What you have
said in my opinion is that the 1 comes out BECAUSE THERE IS
AN INT OBJECT IN THE PLACE IN MEMORY WHERE THE STORE WAS DONE.
It is this object that holds the 1 value and it has
an INSTRINSIC type "int". The C Standard denies this.
It can no more distinguish the above (legal) code from the
(illegal) code:
void f() {
int *pi = malloc(sizeof(float)+sizeof(int));
*pi = 1;
float * pf = (float*)(void*)pi;
printf("%f", *pf);
}
because "the type of the object denoted by *pf is float"
follows from the Standard. I dont see that the aliasing
rules exclude this code, since while *pi is an alias
for *pf, neither is a declared variable, and the aliasing
rules only apply to _declared_ variables.
Now, MY rules make this second example illegal because a float lvalue
may NOT be used to access an int object, and the object
HAS the type int BECAUSE an int value was stored there.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 5 Jul 1994 20:11:05 GMT Raw View
In article <2vacsa$aaj@usenet.pa.dec.com> diamond@jrd.dec.com (Norman Diamond) writes:
>That is indeed true, ANSI Classic section 3.3, page 39 lines 22 to 24,
>allow accesses to integral objects via lvalues that differ in signedness
>and/or have more qualifications than the actual objects, but do not make
>related allowances for pointers to integral objects.
>
>However, even though the access is allowed, it is not entirely clear if
>the resulting value makes any sense. For values in the intersection of
>the signed and unsigned types, probably yes. For other values, for most
>practical purposes yes (though the effect depends on one's vs two's
>complement etc.) but for the purposes of the standard it is not clear.
It makes sense as follows: the Standard can simply
specify that the value is "unspecified". Whatever that
means, it promises that you WILL NOT GET A CORE DUMP.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 5 Jul 1994 20:18:22 GMT Raw View
In article <CsGzp3.1wA@crdnns.crd.ge.com> volpe@ausable.crd.ge.com writes:
>>
>> I'm sorry that you do not understand my explanation
>>of the problem. Please try.
>>
>> void f() {
>> int *pi = malloc(sizeof(int));
>> *pi = 1;
>> printf("%d", *pi);
>> }
>>
>>Nothing in the C Standard promises that the output will be "1".
>>As far as I know. Please point out the words that contradict
>>this assertion if you can, thus educating me.
>
>The entire standard, taken as a whole, promises this.
No, it does not, as far as I can tell.
>"*pi" is an int.
So what. *pi exists only when the expression it contains
is executed. After that, no object exists. So there is no
object which persists to retain the value 1.
Auto and static objects persist. The C Standard defines
their lifetimes and it DENIES EXPLICITLY the existence
of other objects.
*pi is not auto.
*pi is not static.
Therefore it is not an object. Contradiction.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Wed, 6 Jul 1994 06:47:57 GMT Raw View
In article <9418518.3625@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>rfg@netcom.com (Ronald F. Guilmette) writes:
>
>>As far as general
>>rules go, all one can say is that pretending a `signed int' is in fact an
>>`unsigned int' can lead to trouble (and probably should be discouraged...
>>just as the C standard already attempts to do).
>
>Well, since it does define the behaviour in some of these
>int/unsigned cases, I wouldn't call it strong discouragement.
>
>However, the C standard apparently doesn't define the behaviour at all if
>you pretend that a `signed int *' is in fact an `unsigned int *',
>e.g.
>
> #include <stdio.h>
> int main() {
> int x = 1;
> int *i;
> *(unsigned **)&i = (unsigned *) &x;
> printf("%d", *i);
> return 0;
> }
>
>Now would it really be a burden on implementors if C++ allowed
>programmers to do this?
There is no question that it should be allowed. It's just that the results
in such cases ought to put put into either the pile marked ``undefined
behavior'' or else into the pile marked ``implementation defined behavior''.
>I'm not saying that this would necessarily be
>a good idea, but I imagine that it works with all existing
>implementations, since I expect that they all use the same
>representation for `int *' as they use for `unsigned *'. Please
>correct me if I'm wrong and there really is some reason why
>implementations might want to represent these types differently.
As I've already mentioned, the conversion of any negative value to an
unsigned type value yields results that are (at best) questionable.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: clive@sco.com (Clive D.W. Feather)
Date: Wed, 6 Jul 1994 08:47:03 GMT Raw View
In article <CsHHqM.G2z@ucc.su.OZ.AU>,
John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
> Auto and static objects persist. The C Standard defines
> their lifetimes and it DENIES EXPLICITLY the existence
> of other objects.
> *pi is not auto.
> *pi is not static.
> Therefore it is not an object. Contradiction.
Have you ever read the Standard, or are you just an illiterate idiot ?
Subclause 7.10.3.3:
|| The /malloc/ function allocates space for an object whose size is
|| specified by /size/ and whose value is indeterminate.
"object". O B J E C T. Object.
See ?
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: clive@sco.com (Clive D.W. Feather)
Date: Wed, 6 Jul 1994 09:18:22 GMT Raw View
In article <CsIGEI.Et3@scone.london.sco.com>,
Clive D.W. Feather <clive@sco.com> wrote:
>In article <CsHHqM.G2z@ucc.su.OZ.AU>,
>John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>> Auto and static objects persist. The C Standard defines
>> their lifetimes and it DENIES EXPLICITLY the existence
>> of other objects.
>> *pi is not auto.
>> *pi is not static.
>> Therefore it is not an object. Contradiction.
> Have you ever read the Standard, or are you just an illiterate idiot ?
> Subclause 7.10.3.3:
> || The /malloc/ function allocates space for an object whose size is
> || specified by /size/ and whose value is indeterminate.
On second thoughts, I retract the term "idiot" and apologise for it. I've
just looked at 6.1.2.4, and it does indeed say:
|| An object has a *storage duration* that determines its lifetime.
|| There are two storage durations, static and automatic.
This is a Defect. There are *three* storage durations [1]: static, automatic,
and heap. Malloced objects have heap storage duration. A Defect Report
will be submitted.
Moral: when making assertions like "DENIES EXPLICITLY", give references
so that we can see what you are talking about. I was about to flame this
statement for ignoring extern and register objects.
[1] Nobody expects the Spanish Inquisition.
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: clive@sco.com (Clive D.W. Feather)
Date: Wed, 6 Jul 1994 09:09:35 GMT Raw View
In article <CsHH02.EzD@ucc.su.OZ.AU>,
John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>>> void f() {
>>> int *pi = malloc(sizeof(int));
>>> *pi = 1;
>>> printf("%d", *pi);
>>> }
> What you have
> said in my opinion is that the 1 comes out BECAUSE THERE IS
> AN INT OBJECT IN THE PLACE IN MEMORY WHERE THE STORE WAS DONE.
> It is this object that holds the 1 value and it has
> an INSTRINSIC type "int". The C Standard denies this.
There is no concept of an INSTRINSIC [sic] type in the Standard. I'll
try, just once, to explain what's happening.
The Standard talks about "objects", which are blocks of memory. Supposing
sizeof (int) is 4, then "int i;" generates a block of 4 bytes, which the
compiler refers to as "i". Similarly, "malloc (4)" generates a block of
4 bytes, and malloc returns the address of the first of those four
bytes.
When you write "i = 1;" or "*pi = 1", you say:
* Take the block of memory referred to by i, or whose first byte is
pointed to by pi.
* *Treating it as an int*, set its value to 1.
Neither block of memory has an "intrinsic type". In each case, the type
of the assignment is deduced by the type of the left hand side, which is
"int" in each case.
> It can no more distinguish the above (legal) code from the
> (illegal) code:
> void f() {
> int *pi = malloc(sizeof(float)+sizeof(int));
> *pi = 1;
> float * pf = (float*)(void*)pi;
> printf("%f", *pf);
> }
> because "the type of the object denoted by *pf is float"
> follows from the Standard.
[Ignoring the fact that you have a syntax error, since I know what
you're getting at.]
Not quite. When a block of memory is accessed via the expression "*pf",
it is done so using float operations. This is normally described as
"the type of *pf is float", but there is a distinctions.
This code is illegal, not because the same object is given two types,
but because the value is being accessed through an lvalue with a
different type. Note that the following code is perfectly legal:
void f() {
int *pi = malloc(sizeof(float)+sizeof(int));
float * pf;
*pi = 1;
pf = (float*)(void*)pi;
*pf = 1;
printf("%f", *pf);
}
The malloced object is still given two types, but every time its value
is examined, it is done so through the type it was stored with.
This code is also legal:
void f() {
int *pi = malloc(sizeof(float)+sizeof(int));
const volatile unsigned int * pcvui;
*pi = 1;
pcvui = (const volatile unsigned int *)(void*)pi;
printf("%f", *pcvui);
}
because a value can be accessed through an lvalue with qualified type
and with a change in the signedness.
> I dont see that the aliasing
> rules exclude this code, since while *pi is an alias
> for *pf, neither is a declared variable, and the aliasing
> rules only apply to _declared_ variables.
Where on earth did you get that stupid idea. The aliasing rules apply to
*objects*. *READ* subclause 6.3, don't reinvent it.
> Now, MY rules make this second example illegal because a float lvalue
> may NOT be used to access an int object, and the object
> HAS the type int BECAUSE an int value was stored there.
We're not playing by your rules.
Thankfully.
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: alan@rcp.co.uk (Alan Stokes)
Date: Wed, 6 Jul 94 11:02:01 GMT Raw View
In <CsHHqM.G2z@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>In article <CsGzp3.1wA@crdnns.crd.ge.com> volpe@ausable.crd.ge.com writes:
>>>
>>> I'm sorry that you do not understand my explanation
>>>of the problem. Please try.
>>>
>>> void f() {
>>> int *pi = malloc(sizeof(int));
>>> *pi = 1;
>>> printf("%d", *pi);
>>> }
>>>
>>>Nothing in the C Standard promises that the output will be "1".
>>>As far as I know. Please point out the words that contradict
>>>this assertion if you can, thus educating me.
> Auto and static objects persist. The C Standard defines
>their lifetimes and it DENIES EXPLICITLY the existence
>of other objects.
Where? The definition of object (ANSI classic 1.6) just says an object is a
region of storage. 4.10.3.3. specifies that malloc() allocates space for an
object and returns a pointer to it; that seems pretty clear to me.
> *pi is not auto.
> *pi is not static.
>Therefore it is not an object. Contradiction.
Even if the standard does say this it would contradict what 4.10.3.3 says,
and so a Defect Report would be in order (except that we all know what the
answer would be).
--
Alan Stokes (alan@rcp.co.uk)
Richards Computer Products Ltd
Didcot, UK
Author: ark@tempel.research.att.com (Andrew Koenig)
Date: Wed, 6 Jul 1994 12:48:19 GMT Raw View
In article <rfgCsIAvx.2MB@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
> As I've already mentioned, the conversion of any negative value to an
> unsigned type value yields results that are (at best) questionable.
Not at all. The conversion is defined by arithmetic modulo 2^n,
where n is the number of bits in the unsigned type.
--
--Andrew Koenig
ark@research.att.com
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 29 Jun 1994 17:48:57 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>jason@cygnus.com (Jason Merrill) writes:
>>>>>>> John Max Skaller <maxtal@physics.su.OZ.AU> writes:
>>
>>> int and unisgned have the same object type. I'm told int* and
>>> unsigned* do not. So a reinterpret cast between them will be undefined.
>
> Yes. Note I dont AGREE with that but its the rule
>Bill Plauger says is correct for ISO C. I prefer a rule:
>
> "if T1 and T2 have the same object type, then
> so too do pointers to those types"
>
>which rule is recusive on pointers and appeals to my sense
>of mathematical symmetry.
Regardless of the mathematical symmetry, I think it's a good rule,
because it captures what implementations will do: implementations
will only care about the object types of the things pointed to.
[...(char*) to (int*) is undefined since ]
>Bill says the same applies to int* and unsigned* -- I cant
>understand exactly why, or how two pointers to the SAME
>object type could have distinct representations, but that
>doesnt mean I'm right and Bill and/or ISO C is wrong and should
>be changed.
I know that I have said here that unless there is a good reason, C++
should have the same rules as C for the C subset. But in this case, I
think there *are* good reasons to allow an extension to ISO C: the
casts in question are probably quite useful to programmers, but
disallowing them isn't at all useful to implementors. In fact, I would
be extremely suprised if there were *any* existing C or C++
implementations which represented any pointers to the same object type
differently.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: clive@scone.london.sco.com (Clive D.W. Feather)
Date: Thu, 30 Jun 1994 14:20:59 GMT Raw View
In article <9418103.27023@mulga.cs.mu.OZ.AU>,
Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>>>> int and unisgned have the same object type. I'm told int* and
>>>> unsigned* do not. So a reinterpret cast between them will be undefined.
[...]
>> Bill says the same applies to int* and unsigned* -- I cant
>> understand exactly why, or how two pointers to the SAME
>> object type could have distinct representations
In ISO C, int and unsigned are different types (though values that are
in the range of both types have the same representation in both).
Therefore (int *) and (unsigned *) are different types.
The term you need to look for is "compatible type".
Pointers to compatible types with the same qualification are compatible,
so (int *) is compatible with (int *), but not with (unsigned *) or
(int * const).
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: clive@sco.com (Clive D.W. Feather)
Date: Wed, 6 Jul 1994 16:09:52 GMT Raw View
In article <CsIrKK.17z@tempel.research.att.com>,
Andrew Koenig <ark@tempel.research.att.com> wrote:
>In article <rfgCsIAvx.2MB@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>> As I've already mentioned, the conversion of any negative value to an
>> unsigned type value yields results that are (at best) questionable.
> Not at all. The conversion is defined by arithmetic modulo 2^n,
> where n is the number of bits in the unsigned type.
Not in this context (type punning).
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: volpe@bart.crd.ge.com (Christopher R. Volpe)
Date: Wed, 6 Jul 1994 19:06:54 GMT Raw View
In article <rfgCsIAvx.2MB@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
>>However, the C standard apparently doesn't define the behaviour at all if
>>you pretend that a `signed int *' is in fact an `unsigned int *',
>>e.g.
>>
>> #include <stdio.h>
>> int main() {
>> int x = 1;
>> int *i;
>> *(unsigned **)&i = (unsigned *) &x;
>> printf("%d", *i);
>> return 0;
>> }
>>
>>Now would it really be a burden on implementors if C++ allowed
>>programmers to do this?
>
>There is no question that it should be allowed. I
I question it. Is there something in the Standard that requires "int *" and
"unsigned int *" to have the same representation? The above uses trickery to
"pretend" that an the storage occupied by an int* object is really an unsigned
int *.
>t's just that the results
>in such cases ought to put put into either the pile marked ``undefined
>behavior''
It's allowed, but results in undefined behavior? This must be some strange
definition of the word "allow" with which I was prefiously unfamiliar.
>or else into the pile marked ``implementation defined behavior''.
>
>>I'm not saying that this would necessarily be
>>a good idea, but I imagine that it works with all existing
>>implementations, since I expect that they all use the same
>>representation for `int *' as they use for `unsigned *'. Please
>>correct me if I'm wrong and there really is some reason why
>>implementations might want to represent these types differently.
>
>As I've already mentioned, the conversion of any negative value to an
>unsigned type value yields results that are (at best) questionable.
It does? How so? The result is well defined by the Standard.
--
Chris Volpe Phone: (518) 387-7766 (Dial Comm 8*833
GE Corporate R&D Fax: (518) 387-6560
PO Box 8, Schenectady, NY 12301 Email: volpecr@crd.ge.com
Author: clive@sco.com (Clive D.W. Feather)
Date: Thu, 7 Jul 1994 06:44:59 GMT Raw View
In article <CsJ93J.K4v@crdnns.crd.ge.com>,
Christopher R. Volpe <volpe@ausable.crd.ge.com> wrote:
>>> *(unsigned **)&i = (unsigned *) &x;
> I question it. Is there something in the Standard that requires "int *" and
> "unsigned int *" to have the same representation?
No, there isn't. However, since non-negative int values must have the
same representation as unsigned ints, I feel that it ought to be
required (int and unsigned int are "half compatible"; they should be
compatible types when holding values in the common range).
>>> representation for `int *' as they use for `unsigned *'. Please
>>> correct me if I'm wrong and there really is some reason why
>>> implementations might want to represent these types differently.
>> As I've already mentioned, the conversion of any negative value to an
>> unsigned type value yields results that are (at best) questionable.
> It does? How so? The result is well defined by the Standard.
This situation isn't a conversion in that sense. In particular, it is
quite possible for "(unsigned)-1" to have a different bit pattern to
"(int)-1". I can't see any reason for (int *) and (unsigned *) to have
different representations, but I will admit that the Standard permits it.
--
Clive D.W. Feather | Santa Cruz Operation | If you lie to the compiler,
clive@sco.com | Croxley Centre | it will get its revenge.
Phone: +44 923 816 344 | Hatters Lane, Watford | - Henry Spencer
Fax: +44 923 210 352 | WD1 8YN, United Kingdom |
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Thu, 7 Jul 1994 16:14:59 GMT Raw View
volpe@bart.crd.ge.com (Christopher R. Volpe) writes:
>rfg@netcom.com (Ronald F. Guilmette) writes:
>>Fergus Henderson writes:
>>>However, the C standard apparently doesn't define the behaviour at all if
>>>you pretend that a `signed int *' is in fact an `unsigned int *'.
>>>
>>>Now would it really be a burden on implementors if C++ allowed
>>>programmers to do this?
>>
>>There is no question that it should be allowed. I
>
>I question it. Is there something in the Standard that requires "int *" and
>"unsigned int *" to have the same representation?
No, as far as I'm aware there isn't anything in the C standard which
requires this - but that's exactly the question: *should* there be?
Should the C++ standard add this requirement?
>>t's just that the results
>>in such cases ought to put put into either the pile marked ``undefined
>>behavior''
>
>It's allowed, but results in undefined behavior? This must be some strange
>definition of the word "allow" with which I was prefiously unfamiliar.
>
>>or else into the pile marked ``implementation defined behavior''.
Or else the pile marked ``unspecified result'' (but defined behaviour -
i.e. no core dump).
>>>I'm not saying that this would necessarily be
>>>a good idea, but I imagine that it works with all existing
>>>implementations, since I expect that they all use the same
>>>representation for `int *' as they use for `unsigned *'. Please
>>>correct me if I'm wrong and there really is some reason why
>>>implementations might want to represent these types differently.
>>
>>As I've already mentioned, the conversion of any negative value to an
>>unsigned type value yields results that are (at best) questionable.
So? Why would this mean that implementations might want to represent
`int *' and `unsigned *' differently?
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: volpe@bart.crd.ge.com (Christopher R. Volpe)
Date: Fri, 8 Jul 1994 03:09:10 GMT Raw View
In article <CsK5F1.J3w@scone.london.sco.com>, clive@sco.com (Clive D.W. Feather) writes:
>In article <CsJ93J.K4v@crdnns.crd.ge.com>,
>Christopher R. Volpe <volpe@ausable.crd.ge.com> wrote:
>>>> *(unsigned **)&i = (unsigned *) &x;
>> I question it. Is there something in the Standard that requires "int *" and
>> "unsigned int *" to have the same representation?
>
>No, there isn't. However, since non-negative int values must have the
>same representation as unsigned ints, I feel that it ought to be
>required (int and unsigned int are "half compatible"; they should be
>compatible types when holding values in the common range).
Ok.
>>> As I've already mentioned, the conversion of any negative value to an
>>> unsigned type value yields results that are (at best) questionable.
>> It does? How so? The result is well defined by the Standard.
>
>This situation isn't a conversion in that sense. In particular, it is
>quite possible for "(unsigned)-1" to have a different bit pattern to
>"(int)-1". I can't see any reason for (int *) and (unsigned *) to have
>different representations, but I will admit that the Standard permits it.
How's this: Ints are stored as sign-magnitude numbers. Thus, 01......1 is
INT_MAX, 10......0 is negative 0, 10....01 is negative 1, 1.......1 is
INT_MIN. Then (int)-1 is 10....01, but (unsigned)-1 is still required to
be 1.......1.
--
Chris Volpe Phone: (518) 387-7766 (Dial Comm 8*833
GE Corporate R&D Fax: (518) 387-6560
PO Box 8, Schenectady, NY 12301 Email: volpecr@crd.ge.com
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Fri, 8 Jul 1994 07:15:42 GMT Raw View
In article <CsIrKK.17z@tempel.research.att.com> ark@tempel.research.att.com (Andrew Koenig) writes:
>In article <rfgCsIAvx.2MB@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>
>> As I've already mentioned, the conversion of any negative value to an
>> unsigned type value yields results that are (at best) questionable.
>
>Not at all. The conversion is defined by arithmetic modulo 2^n,
>where n is the number of bits in the unsigned type.
First Andrew let me clarify that my statement was made with respect to
the ISO C standard, a publically available document upon which (as they
say) the ink is dry. (I have just noticed that this thread has been
cross-posted to *both* the comp.std.c *and* the comp.std.c++ newgroups,
so I feel that it is important to clarify this point. I certainly did
not intend to comment on the rules which may or may not be adopted three
years hence in some as yet fluid standard, and I am especially loath
to do so in the case of C++, given the large number of unwarranted minor
deviations from the ISO C standard now present in current drafts of
that standard.)
Second let me just reestablish the context of this discussion. The
question at issue was the meaningfulness (or lack thereof) of the
conversion of a NEGATIVE value from type `int' to type `unsigned int'.
You seem to be claiming that the ISO C standard makes some guarrantees
with respect to the value yielded by such a conversion. I claim that
there are no such guarrantees offered WITHIN the ISO C standard.
People who actually HAVE a copy of the C standard (including most readers
of comp.std.c) can judge for themselves which one of us knows whereof he
speaks. The relevant section would seem to be 6.2.1.2 in the ISO C
standard (aka 3.2.1.2 in the ``classic'' ANSI C standard).
P.S. I find it rather a pity that even the HP 16C (programmer's model)
calculators operate pretty much exclusively as two's complement machines.
It would be nice if a one's complement version were available. It could
become a `standard issue' item for framers of programming language
standards. Oh well, there are probably still a few CDC machines (3150's
anyone?) lying about somewhere which can be used for reference. (1/2 :-)
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Fri, 8 Jul 1994 07:34:11 GMT Raw View
In article <CsJ93J.K4v@crdnns.crd.ge.com> volpe@ausable.crd.ge.com writes:
>In article <rfgCsIAvx.2MB@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
>>>However, the C standard apparently doesn't define the behaviour at all if
>>>you pretend that a `signed int *' is in fact an `unsigned int *',
>>>e.g.
>>>
>>> #include <stdio.h>
>>> int main() {
>>> int x = 1;
>>> int *i;
>>> *(unsigned **)&i = (unsigned *) &x;
>>> printf("%d", *i);
>>> return 0;
>>> }
>>>
>>>Now would it really be a burden on implementors if C++ allowed
>>>programmers to do this?
>>
>>There is no question that it should be allowed. I
>
>I question it.
OK. That is certainly your privledge. I might point out however that
the ISO C standard is (I think) fairly clear that the only real re-
strictions that have ever been placed on casts are that the operand
must have some scalar type and that the cast itself must specify some
scalar type.
>>It's just that the results
>>in such cases ought to put put into either the pile marked ``undefined
>>behavior''
>
>It's allowed, but results in undefined behavior? This must be some strange
>definition of the word "allow" with which I was prefiously unfamiliar.
Well, welcome to procedural programming languages! Most such languages
``allow'' you to try to use the value stored in an uninitialized variable,
but the results when you do this are never claimed to be in the least bit
predictable.
In ISO C, there are *zillions* of such things... i.e. things that you *can*
do (and which no standard conforming compiler is obliged to give you any
warnings or errors about) but whose results are, at best, somewhat un-
predictable (either from platform to platform, or from compiler to com-
piler, or from run to run). All pointer type casts in C (which convert
one type of pointer to a different type of pointer) fall into this cate-
gory IF you subsequently try to dereference the converted result pointer.
Such dereferences are defined to result in undefined behavior.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: barrett@lucy.ee.und.ac.za (Alan Barrett)
Date: 8 Jul 1994 10:44:00 +0200 Raw View
In article <rfgCsM1I7.D6H@netcom.com>,
rfg@netcom.com (Ronald F. Guilmette) writes:
> Second let me just reestablish the context of this discussion. The
> question at issue was the meaningfulness (or lack thereof) of the
> conversion of a NEGATIVE value from type `int' to type `unsigned int'.
I thought that the issue was the meaningfulness (or lack thereof)
of the use of techniques commonly referred to as "type punning" to
reinterpret a negative-valued integer as if it were an unsigned integer.
I believe that type punning is not a "conversion" in the sense of
ANSI/ISO 9899-1990 section 6.2.
> You seem to be claiming that the ISO C standard makes some guarrantees
> with respect to the value yielded by such a conversion. I claim that
> there are no such guarrantees offered WITHIN the ISO C standard.
I believe that the second paragraph of section 6.2.1.2 makes some very
clear guarantees about the behaviour of a *conversion* from a negative
signed integer to an unsigned integer, and that those guarantees accord
with what Andrew Koenig said about arithmetic modulo 2**n.
I am not aware of any guarantees about type punning between
negative-valued signed integers and unsigned integers, and that accords
with what Ronald Guilmette says, except that Ronald seems to be using
the term "conversion" to refer to something that I would not call a
conversion.
--apb
Alan Barrett, Dept. of Electronic Eng., Univ. of Natal, Durban, South Africa
RFC822: barrett@ee.und.ac.za
Author: volpe@bart.crd.ge.com (Christopher R. Volpe)
Date: Fri, 8 Jul 1994 12:33:08 GMT Raw View
In article <CsLq3B.LMA@crdnns.crd.ge.com>, I wrote:
>In article <CsK5F1.J3w@scone.london.sco.com>, clive@sco.com (Clive D.W. Feather) writes:
>>>> As I've already mentioned, the conversion of any negative value to an
>>>> unsigned type value yields results that are (at best) questionable.
>>> It does? How so? The result is well defined by the Standard.
>>
>>This situation isn't a conversion in that sense. In particular, it is
>>quite possible for "(unsigned)-1" to have a different bit pattern to
>>"(int)-1". I can't see any reason for (int *) and (unsigned *) to have
>>different representations, but I will admit that the Standard permits it.
>
>
>How's this: Ints are stored as sign-magnitude numbers. Thus, 01......1 is
>INT_MAX, 10......0 is negative 0, 10....01 is negative 1, 1.......1 is
>INT_MIN. Then (int)-1 is 10....01, but (unsigned)-1 is still required to
>be 1.......1.
Ignore the above brain damage. It was late when I wrote it.
Thanks to Clive for pointing it out.
-Chris
--
Chris Volpe Phone: (518) 387-7766 (Dial Comm 8*833
GE Corporate R&D Fax: (518) 387-6560
PO Box 8, Schenectady, NY 12301 Email: volpecr@crd.ge.com
Author: volpe@bart.crd.ge.com (Christopher R. Volpe)
Date: Fri, 8 Jul 1994 18:33:28 GMT Raw View
In article <rfgCsM2Cz.ED0@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <CsJ93J.K4v@crdnns.crd.ge.com> volpe@ausable.crd.ge.com writes:
>>In article <rfgCsIAvx.2MB@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
>>>>However, the C standard apparently doesn't define the behaviour at all if
>>>>you pretend that a `signed int *' is in fact an `unsigned int *',
>>>>e.g.
>>>>
>>>> #include <stdio.h>
>>>> int main() {
>>>> int x = 1;
>>>> int *i;
>>>> *(unsigned **)&i = (unsigned *) &x;
>>>> printf("%d", *i);
>>>> return 0;
>>>> }
>>>>
>>>>Now would it really be a burden on implementors if C++ allowed
>>>>programmers to do this?
>>>
>>>There is no question that it should be allowed. I
>>
>>I question it.
>
>OK. That is certainly your privledge. I might point out however that
>the ISO C standard is (I think) fairly clear that the only real re-
>strictions that have ever been placed on casts are that the operand
>must have some scalar type and that the cast itself must specify some
>scalar type.
I didn't question the cast, it was the subsequent access I questioned.
>
>>>It's just that the results
>>>in such cases ought to put put into either the pile marked ``undefined
>>>behavior''
>>
>>It's allowed, but results in undefined behavior? This must be some strange
>>definition of the word "allow" with which I was prefiously unfamiliar.
>
>Well, welcome to procedural programming languages! Most such languages
>``allow'' you to try to use the value stored in an uninitialized variable,
>but the results when you do this are never claimed to be in the least bit
>predictable.
I guess by "allow", you mean "doesn't evoke a diagnostic". That's not my
definition of "allow".
>
>In ISO C, there are *zillions* of such things... i.e. things that you *can*
>do (and which no standard conforming compiler is obliged to give you any
>warnings or errors about) but whose results are, at best, somewhat un-
Do you consider the language to "allow" X, if a particular implementation if
permitted to reject X? (Undefined behavior includes the possibility of
outright rejection, remember.)
>predictable (either from platform to platform, or from compiler to com-
>piler, or from run to run). All pointer type casts in C (which convert
>one type of pointer to a different type of pointer) fall into this cate-
>gory IF you subsequently try to dereference the converted result pointer.
>Such dereferences are defined to result in undefined behavior.
>--
>
>-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
>---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
>---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
--
Chris Volpe Phone: (518) 387-7766 (Dial Comm 8*833
GE Corporate R&D Fax: (518) 387-6560
PO Box 8, Schenectady, NY 12301 Email: volpecr@crd.ge.com