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