Bitshifting independant of signedness

F

Frederick Gotham

Just wondering if bitwise operators pay any attention to the signedness of
an integer type? Do they pay any attention to, or work any differently
with, the sign-bit, or with a signed integer type?

Let's take a hypothetical system where:

(1) int is comprised of 32 value bits (inclusive of the sign-bit).
(2) Two's complement is used.

The bit-pattern for -18 on such a system is:

1111 1111 1111 1111 1111 1111 1110 1110

On such a system is the following *guaranteed* to work?

#define VALBITS_INT 31
/* The above figure does NOT
inlude the sign bit. */

int Minus18()
{
int i = 0;

/* (1) First set the sign-bit: */

i |= 1U << VALBITS_INT;
/* Will this definitely set the sign-bit?
Is the U tag necessary on the literal? */

/* (2) Set all other bits to 1: */

int const MSBonly = 1 << VALBITS_INT-1;

i |= MSBonly | MSBonly-1;

/* (3) Toggle first and fifth bits */

i ^= 1;
i ^= 16;

return i;
}

When performing a bitwise operation, are the integer types treated as if
they're unsigned?
 
M

Michael Mair

Frederick said:
Just wondering if bitwise operators pay any attention to the signedness of
an integer type? Do they pay any attention to, or work any differently
with, the sign-bit, or with a signed integer type?

Let's take a hypothetical system where:

(1) int is comprised of 32 value bits (inclusive of the sign-bit).
(2) Two's complement is used.
(3) You assume that there are no padding bits in signed int
that are not also there in unsigned int.
(4) You assume that INT_MAX+1U != 0 (the "and vice versa"
part for (3))
The bit-pattern for -18 on such a system is:

1111 1111 1111 1111 1111 1111 1110 1110

On such a system is the following *guaranteed* to work?

#define VALBITS_INT 31
/* The above figure does NOT
inlude the sign bit. */

int Minus18()
{
int i = 0;

/* (1) First set the sign-bit: */

i |= 1U << VALBITS_INT;
/* Will this definitely set the sign-bit?
Is the U tag necessary on the literal? */

Depends. The 1U will be detrimental if (4) does not hold as
you would then shift "too far".
/* (2) Set all other bits to 1: */

int const MSBonly = 1 << VALBITS_INT-1;

i |= MSBonly | MSBonly-1;

Will not set all bits if (3) does not hold.
i = ~0;
certainly works better in that respect.
/* (3) Toggle first and fifth bits */

i ^= 1;
i ^= 16;

return i;
}

When performing a bitwise operation, are the integer types treated as if
they're unsigned?

No. Note that you could "assemble" the representation and then
reinterpret it:
int i;
unsigned int u = -1;
unsigned neg = 18;
u ^= (neg - 1U);
i = *(int *)&u;
This needs (1) to (4) as well.


Cheers
Michael
 
P

pete

Frederick said:
Just wondering if bitwise operators pay any attention to the signedness of
an integer type? Do they pay any attention to, or work any differently
with, the sign-bit, or with a signed integer type?

Let's take a hypothetical system where:

(1) int is comprised of 32 value bits (inclusive of the sign-bit).
(2) Two's complement is used.

The bit-pattern for -18 on such a system is:

1111 1111 1111 1111 1111 1111 1110 1110

On such a system is the following *guaranteed* to work?

#define VALBITS_INT 31
/* The above figure does NOT
inlude the sign bit. */

int Minus18()
{
int i = 0;

/* (1) First set the sign-bit: */

i |= 1U << VALBITS_INT;
/* Will this definitely set the sign-bit?
Is the U tag necessary on the literal? */

I think your attempt is undefined.
/* (2) Set all other bits to 1: */

int const MSBonly = 1 << VALBITS_INT-1;

i |= MSBonly | MSBonly-1;

/* (3) Toggle first and fifth bits */

i ^= 1;
i ^= 16;

return i;
}

When performing a bitwise operation,
are the integer types treated as if
they're unsigned?

No.

Setting the sign bit with a left shift, looks undefined to me.

N869
6.5.7 Bitwise shift operators

[#4] The result of E1 << E2 is E1 left-shifted E2 bit
positions; vacated bits are filled with zeros. If E1 has an
unsigned type, the value of the result is E1×2E2, reduced
modulo one more than the maximum value representable in the
result type. If E1 has a signed type and nonnegative value,
and E1×2E2 is representable in the result type, then that is
the resulting value; otherwise, the behavior is undefined.
 
F

Frederick Gotham

Michael Mair posted:
(3) You assume that there are no padding bits in signed int
that are not also there in unsigned int.

I said it had 32 value bits, not 32 object bits.
 
M

Michael Mair

Frederick said:
Michael Mair posted:


I said it had 32 value bits, not 32 object bits.

Yes. However, only the common range of unsigned int and signed
int is guaranteed to have the same representation.
I do not find anything in the standard against either
signed: sign bit -- four padding bits -- 31 value bits
unsigned: five padding bits -- 31 value bits
or
signed: sign bit -- four padding bits -- 31 value bits
unsigned: four padding bits -- 32 value bits
or
signed: sign bit -- four padding bits -- 31 value bits
unsigned: 36 value bits
or, what you were hoping for
signed: sign bit -- four padding bits -- 31 value bits
unsigned: one value bit -- four padding bits -- 31 value bits
where the above specifies the "bit order" of the representation.
So, without the stipulation that unsigned has one more value
bit than signed int and that that additional value bit is
"in the same place" as the sign bit of the signed int, your
expectations may be off.
You may shift too far for identical numbers of value bits in
the first of the above cases. Or you may fail to set the "sign
bit" in the second case.

Cheers
Michael
 

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

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top