From: ImpalerCore on 7 Dec 2009 02:58 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 7 Dec 2009 18:14 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 8 Dec 2009 07:31 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 8 Dec 2009 08:55 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 8 Dec 2009 09:21 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! ]
|
Next
|
Last
Pages: 1 2 Prev: C++, C99 and floating point exceptions Next: C++ analog of setvbuf() ? |