From: ImpalerCore on
I have some macros that use the construct '~((-1) << (WIDTH))' to
generate masks. I was informed that left-shifting a signed negative
value is undefined behavior, and recommended that I replace (-1) with
(~0UL). I'm not familiar with the standard, so can someone explain
this more?

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: SG on
On 7 Dez., 20:58, ImpalerCore <jadil...(a)gmail.com> wrote:
> I have some macros that use the construct '~((-1) << (WIDTH))' to
> generate masks. I was informed that left-shifting a signed negative
> value is undefined behavior,

Undefined behaviour? No, it's "just" implementation-defined. The
thing is that for negative members there's no standardized mapping
value representation. Options are 1's complement, 2's complement and
sign+magnitude.

> and recommended that I replace (-1) with (~0UL).

Possible. You also changed the type from int to long, though.
Another possibility is "unsigned(-1)" but "~0u" is obviously shorter.
A conversion from signed to unsigned practically results in a 2's
complement value representation. This follows from the "modulo rule"
which says that the final value should be equal to the original value
modulo pow(2,N) where N is the number of bits of the destination
type's value representation. Note: This rule only applies to
conversions of integral types to other *unsigned* types. If you have
an unsigned character of value 128 and convert it to a signed char
where SCHAR_MAX is only 127 the result is -- again -- implementation-
defined. In case your machine uses 2's complement it will almost
certainly just reinterpret the bit pattern leading to -128.

Cheers,
SG


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Seungbeom Kim on
ImpalerCore wrote:
> I have some macros that use the construct '~((-1) << (WIDTH))' to
> generate masks. I was informed that left-shifting a signed negative
> value is undefined behavior, and recommended that I replace (-1) with
> (~0UL). I'm not familiar with the standard, so can someone explain
> this more?

"The behavior is undefined if the right operand is negative, or greater
than or equal to the length in bits of the promoted left operand." (5.8/1)
However the standard does not say the behavior of left-shifting a signed
negative value is undefined.

--
Seungbeom Kim

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Greg Herlihy on
On Dec 7, 2:58 pm, ImpalerCore <jadil...(a)gmail.com> wrote:
> I have some macros that use the construct '~((-1) << (WIDTH))' to
> generate masks. I was informed that left-shifting a signed negative
> value is undefined behavior, and recommended that I replace (-1) with
> (~0UL). I'm not familiar with the standard, so can someone explain
> this more?

Left-shifting a negative value has undefined behavior in C, not in C+
+. In C++, bit shifting is a bit-pattern transformation, so however
negative integer values happen to be represented in a particular
implementation, makes no difference.

Greg


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: ImpalerCore on
On Dec 8, 6:14 am, SG <s.gesem...(a)gmail.com> wrote:
> On 7 Dez., 20:58, ImpalerCore <jadil...(a)gmail.com> wrote:
>
> > I have some macros that use the construct '~((-1) << (WIDTH))' to
> > generate masks. I was informed that left-shifting a signed negative
> > value is undefined behavior,
>
> Undefined behaviour? No, it's "just" implementation-defined. The
> thing is that for negative members there's no standardized mapping
> value representation. Options are 1's complement, 2's complement and
> sign+magnitude.
>
> > and recommended that I replace (-1) with (~0UL).
>
> Possible. You also changed the type from int to long, though.
> Another possibility is "unsigned(-1)" but "~0u" is obviously shorter.
> A conversion from signed to unsigned practically results in a 2's
> complement value representation. This follows from the "modulo rule"
> which says that the final value should be equal to the original value
> modulo pow(2,N) where N is the number of bits of the destination
> type's value representation. Note: This rule only applies to
> conversions of integral types to other *unsigned* types. If you have
> an unsigned character of value 128 and convert it to a signed char
> where SCHAR_MAX is only 127 the result is -- again -- implementation-
> defined. In case your machine uses 2's complement it will almost
> certainly just reinterpret the bit pattern leading to -128.

I had used the construct without incident on a 32-bit system, but now
I'm working on an embedded compiler where the standard integer is 16-
bit, and was pointed out that WIDTHs larger than 16 would not work
properly when attempting to use it with 32-bit long integers.

i.e. An example macro that I use for extracting a bit-field

#define EXTRACT_BIT_FIELD(WORD, INDEX, WIDTH) ( (WORD >> (INDEX)) & ~
((-1) << (WIDTH)) )

the -1 is replaced with ~0UL to make sure that 32-bit long integers
works.

#define EXTRACT_BIT_FIELD(WORD, INDEX, WIDTH) ( (WORD >> (INDEX)) & ~
((~0UL) << (WIDTH)) )

Not sure if I take a hit in performance if I extract bitfields from an
8-bit or 16-bit integer when using a 32-bit mask in (~0UL). Maybe
someone knows a more portable way to do it.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]