On Thu, 06 Dec 2007 23:09:24 +0100, jacob navia <ja***@nospam.com>
wrote in comp.lang.c:
I posted this to comp.std.c, but may be of interest here too:
Consider this:
extern void abort(void);
int main (void)
{
unsigned long long xx;
unsigned long long *x = (unsigned long long *) &xx;
*x = -3;
*x = *x * *x;
if (*x != 9)
abort ();
return(0);
}
lcc-win interprets
*x = -3;
as
*x = 4294967293;
since x points to an UNSIGNED long long.
I cast the 32 bit integer -3 into an unsigned integer
then I cast the result to an unsigned long long.
Apparently gcc disagrees.
Am I doing something wrong somewhere?
Yes, I believe you are.
The C standard's wording on initializing scalars (6.7.8 P11) states:
"The initializer for a scalar shall be a single expression, optionally
enclosed in braces. The initial value of the object is that of the
expression (after conversion); the same type constraints and
conversions as for simple assignment apply, taking the type of the
scalar to be the unqualified version of its declared type."
Referring to "Simple assignment" 6.5.26.2 P2:
"In simple assignment (=), the value of the right operand is converted
to the type of the assignment expression and replaces the value stored
in the object designated by the left operand."
Putting these together, the integer constant expression -3, of type
int, is converted to type unsigned long long. There are no
intermediate conversions specified or implied to unsigned int or
signed long long. Your compiler might take these intermediate steps,
under the as-if rule, but only if you produce the same results as a
direct conversion.
And the correct result is (ULLONG_MAX + 1) - 3;
I should first cast into a long long THEN into an unsigned
long long?
No, I think not. What would the result be if you had written either
of these:
*x = -3ULL;
....or:
*x = (unsigned long long)3;
I think you are getting hung up on the details of how you code the
conversion in your compiler, and losing sight of the meaning of the
expression in the language.
The conversion, like all such in C, is defined in terms of value, not
of steps or types to achieve it.
As a practical matter, I suspect the simplest method to get the
correct result would be to convert the signed int constant to signed
long long, then to unsigned long long.
Note the following program, and its output when run in VS 2005
Express, which does not support much of C99 but does support the long
long types:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
unsigned long long x = (unsigned int)-3;
unsigned long long y = (unsigned long long)-3;
unsigned long long z = -3;
unsigned long long a = (long long)-3;
printf("x = %llu\ny = %llu\nz = %llu\na = %llu\n",
x, y, z, a);
return 0;
}
Output:
x = 4294967293
y = 18446744073709551613
z = 18446744073709551613
a = 18446744073709551613
So I suspect your compiler will generate the proper value using the
signed int to signed long long to unsigned long long series of
conversions.
Thanks for your help.
You're welcome.
--
Jack Klein
Home:
http://JK-Technology.Com
FAQs for
comp.lang.c
http://c-faq.com/
comp.lang.c++
http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html