bitwise complement

S

subramanian

Consider the following code:

#include<stdio.h>

int main(void)
{
unsigned char c = 0;

unsigned int i = ~c;

printf("i = %u\n", i);

return 0;

}

I compiled and ran this with 32-bit VC++ and 32-bit gcc.

In both cases, this code prints 4294967295(which is 2^32 - 1) -
UINT_MAX.

My doubt: since we are taking ~c, should't 255 be assigned to i.
 
R

Random832

2006-12-20 said:
Consider the following code:

#include<stdio.h>

int main(void)
{
unsigned char c = 0;
unsigned int i = ~c;
printf("i = %u\n", i);
return 0;
}

I compiled and ran this with 32-bit VC++ and 32-bit gcc.

In both cases, this code prints 4294967295(which is 2^32 - 1) -
UINT_MAX.

My doubt: since we are taking ~c, should't 255 be assigned to i.

Whenever a value of char or short type is used in an expression, it
is silently converted to int. This is ridiculous, but required by the
standard.

So, when you use c, it becomes 0 as an int, then ~c is unspecified
(implementation-defined?) but apparently interpreted by your
implementation as -1, then when assigning to an unsigned int, -1 becomes
UINT_MAX.
 
B

Barry

subramanian said:
Consider the following code:

#include<stdio.h>

int main(void)
{
unsigned char c = 0;

unsigned int i = ~c;

printf("i = %u\n", i);

return 0;

}

I compiled and ran this with 32-bit VC++ and 32-bit gcc.

In both cases, this code prints 4294967295(which is 2^32 - 1) -
UINT_MAX.

My doubt: since we are taking ~c, should't 255 be assigned to i.

"The result of the ~ operator is the bitwise complement of its (promoted)
operand (that is,
each bit in the result is set if and only if the corresponding bit in the
converted operand is
not set). The integer promotions are performed on the operand, and the
result has the
promoted type. If the promoted type is an unsigned type, the expression ~E
is equivalent
to the maximum value representable in that type minus E."
 
B

Ben Pfaff

Random832 said:
Whenever a value of char or short type is used in an expression, it
is silently converted to int. This is ridiculous, but required by the
standard.

The precise rule is:

If an int can represent all values of the original type, the
value is converted to an int; otherwise, it is converted to
an unsigned int.

Because a char might have the same range as unsigned int, this
means that a char could be promoted to unsigned int instead of to
int. (But that's certainly an unusual case.)
 
E

Eric Sosman

Random832 said:
Whenever a value of char or short type is used in an expression, it
is silently converted to int. This is ridiculous, but required by the
standard.

Without invoking "promotion" or anything like it, how would
you propose to evaluate

struct { int a : 7; } x = { 42 };
struct { unsigned int b : 13; } y = { 27 };
struct { int c : 11 } z;
z.c = a.x + b.y;

? Find me a machine whose instruction set includes an operation
for "add signed seven-bit integer to unsigned thirteen-bit integer
producing a signed eleven-bit sum" and I'll concede that you've
justified "ridiculous." Until then, I'll stick with "practical."

(Actually, I once worked on a machine that almost did this,
although it didn't distinguish signed and unsigned arithmetic.
The year was 1969 and the words were 48 bits wide, and there
were two distinct program counter registers, and you could get
the program counters to run backwards, and ... well, they don't
make 'em like that any more.)
 
R

Random832

2006-12-21 said:
Without invoking "promotion" or anything like it, how would
you propose to evaluate

struct { int a : 7; } x = { 42 };
struct { unsigned int b : 13; } y = { 27 };
struct { int c : 11 } z;
z.c = a.x + b.y;

Masking. And with the fact that overflows are undefined anyway.

There's no reason, if c is type unsigned char, why ~c should not also be
of type unsigned char.

And there's no reason signedness shouldn't be preserved, though it
didn't matter in the OP's case.
 
J

jaysome

The precise rule is:

If an int can represent all values of the original type, the
value is converted to an int; otherwise, it is converted to
an unsigned int.

Because a char might have the same range as unsigned int, this
means that a char could be promoted to unsigned int instead of to
int. (But that's certainly an unusual case.)

I think it's more common than you think.

On the TI DSPs I've worked with:

#define CHAR_BIT 16
sizeof(int) == 1

On this implementation, if a char is unsigned, then it has the same
range as that of an unsigned int.

Regards
 
E

Eric Sosman

Random832 said:
Masking. And with the fact that overflows are undefined anyway.

Well, that's my point: You (probably) cannot work directly
with the operands in their original sizes, but must first convert
them to some other form and work with that other form. That's
exactly C's model: Convert a "small" operand to a "large" equivalent,
perform "large" arithmetic, and convert the result to "small" again.
I really, truly, cannot see why you think it "ridiculous."
There's no reason, if c is type unsigned char, why ~c should not also be
of type unsigned char.

On a machine with a char-sized accumulator you might be right.
But not all machines have such things, and those whose narrowest
arithmetic is wider than char would incur performance penalties
when evaluating expressions with narrow operands. (A naive code
generator might just insert an AND after each operation; a smarter
one might be able to eliminate some of them.)

Even so, you still need promotion rules to handle expressions
with mixed operand widths -- and as long as you've got to have
promotion rules anyhow, why not use them to simplify arithmetic
elsewhere, too?

Remember: The design of C did not drive the design of the
machines it ran on; 'twas the other way about.
And there's no reason signedness shouldn't be preserved, though it
didn't matter in the OP's case.

The ANSI Committee discussed the issue of value-preserving vs.
signedness-preserving promotions at some length, and (one suspects)
with some vigor. There's a fairly extensive summary of the positions
and their consequences in the Rationale.
 
R

Random832

2006-12-21 said:
The ANSI Committee discussed the issue of value-preserving vs.
signedness-preserving promotions at some length, and (one suspects)
with some vigor. There's a fairly extensive summary of the positions
and their consequences in the Rationale.

In what way does signedness-preserving conflict with preserving the value?
 
K

Keith Thompson

Eric Sosman said:
Without invoking "promotion" or anything like it, how would
you propose to evaluate

struct { int a : 7; } x = { 42 };
struct { unsigned int b : 13; } y = { 27 };
struct { int c : 11 } z;
z.c = a.x + b.y;

? Find me a machine whose instruction set includes an operation
for "add signed seven-bit integer to unsigned thirteen-bit integer
producing a signed eleven-bit sum" and I'll concede that you've
justified "ridiculous." Until then, I'll stick with "practical."
[...]

You could require the result to be the same *as if* the machine had
the appropriate operations. (Defining the semantics of seven-bit
signed plus thirteen-bit unsigned is left as an exercise.)

Or you could limit promotion to cases where an operation has two
operands of different types. Currently, everything shorter than int
is promoted regardless of its context. You could say that, for
example, adding a short and a short yields a short result, with no
promotion.

I'm not saying this would be *better*. It might be conceptually
simpler in some cases. On the other hand, many CPUs don't have
sub-word arithmetic operations anyway, so compiler writers would have
to go to some effort to ensure that the generated code acts as if they
did.
 
E

Eric Sosman

Random832 said:
In what way does signedness-preserving conflict with preserving the value?

"There's a fairly extensive summary of the positions and
their consequences in the Rationale." Section 6.3.1.1, if you're
a Spock-like stickler for precision.
 
C

CBFalconer

Random832 said:
Eric Sosman wrote:
.... snip ...

In what way does signedness-preserving conflict with preserving
the value?

Read N897. I disagree with their conclusions. But it's too late.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,836
Latest member
login dogas

Latest Threads

Top