2

I saw in some code we have a signed value being passed to function (which takes unsigned value). The returned value is again converted back to signed (with the intention of getting the original signed value).. Even though it works currently.. My doubt, will original signed value is retained in this case, in all possible scenarios?

I was told casting is bad, and should be avoided as much as possible.. Can some computer science experts let me know, when this code can be broken?

4

3 回答 3

4

All implementations that I know (after working with C++ for 20+ years on different platforms), convert signed <-> unsigned integer by doing nothing, i.e. the binary value is passed unchanged.

The roots of such behavior is in handling (i.e. not handling) the integer overflows in C. Having such legacy this signed/unsigned conversion is a reasonable thing to do. I do not think this will be changed ever.

To summarize, conversions signed -> unsigned -> signed and unsigned -> signed -> unsigned are 100 % safe. When you have even number of conversions, you either need to take care that the value of the number is a non negative integer that is not using the highest bit, in this case it is not important if the type is signed or unsigned. Otherwise you should explicitly take care of the out of range values with your own code.

于 2013-09-12T19:47:04.760 回答
3

The integer promotions sections of the standards covers conversion of signed and unsigned very well. Your question is tagged C and C++, and though I could dust off both standards, I will show you the relevant portions of the C99 standard here.

Regarding promoting a like-sized signed integer to an unsigned integer where the signed integer is NOT in range of the unsigned integer (i.e. it is less than zero(0)):

C99 6.3.1.3-p2

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

which essentially means "add (UINT_MAX+1)".

For example, on a typical 32 bit system, UINT_MAX is 0xFFFFFFFF. Now suppose you want to convert the following:

int ival = -1;
unsigned int uval = (unsigned int)ival;

According to the standard, ival will be promoted to unsigned int by doing the following:

uval = (UINT_MAX+1) + (-1);

Which of course, results in uval = UINT_MAX;. This is defined by the standard.

Converting to signed from unsigned is a different story. Immediately following the previous section of the standard cited above is:

C99 6.3.1.3-p3

Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

This essentially means you cannot rely on an unsigned conversion to like-size signed result to have implementation-indepentant behavior if the value in the unsigned is not within the allowable range of the signed int. In other words this:

unsigned int uval = INT_MAX;
int val = (int)uval; 

has defined behavior, since INT_MAX is a value within the signed integer range, whereas this:

unsigned int uval = INT_MAX + n;
int val = (int)uval; 

for some arbitrary n such that (INT_MAX+n <= UINT_MAX) is implementation defined. Therefore, don't rely on it. The particular portion of the standard that should scare you into avoiding doing this is the potential for: "an implementation-defined signal is raised". Yikes. Just don't do it.


Examples from the text above

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(int argc, char *argv[])
{
    int ival = -1;
    unsigned int uval = (unsigned int)ival;
    printf("%d : %u\n", ival, uval);

    uval = INT_MAX;
    ival = (int)uval;
    printf("%d : %u\n", ival, uval);

    uval += 1;
    ival = (int)uval;
    printf("%d : %u\n", ival, uval);

    return 0;
}

Output Platform: Apple LLVM version 4.2 (clang-425.0.28)

-1 : 4294967295
2147483647 : 2147483647
-2147483648 : 2147483648
于 2013-09-12T19:52:08.500 回答
1

Conversions from signed to unsigned types are well defined; the result is the original value modulo 2^n, where n is the number of bits in the value representation of the unsigned type. That is, negative values are wrapped to large positive values. However, when you convert from an unsigned to a signed type, if the value being converted can be represented in the target type the value is unchanged; if it can't be represented, the result is implementation defined. So converting a large unsigned value into a signed value that isn't large enough to hold it is not required to produce a negative value.

于 2013-09-12T19:25:07.030 回答