

Why Not Mix Signed and Unsigned Values in C/C++? - pietrofmaggi
http://blog.regehr.org/archives/268

======
mfukar
Unsigned integer types are needed for well defined modular arithmetic, and
signed integer types are needed for, well, negative values of β.

~~~
pietrofmaggi
Signed integer types are,for example, native number format of ARM asm. If you
use unsigned the compiler has to introduce conversion for you.

So your best bet is to always use signed int, excluding when they're not
appropriate ;-)

The real problem, well, what you have to always take in account, is the
"behind the scene" type promotion that any C Compiler has to do. To cope with
this you can put a lot of unnecessary type cast in the code (like when you add
parentesis to formulas just to make clear what is the operator precedence),
but this add a lot of clutter to the code.

~~~
mansr
ARM handles signed and unsigned numbers equally. Addition and subtraction are
the same operation whether signed or unsigned. Multiplication of 32-bit
numbers with 64-bit result has both signed and unsigned versions. Condition
codes can test for both signed and unsigned relations.

As for the real problem, you are right on the mark. Mixing signed and unsigned
can result in a negative number being interpreted as a large positive number
with unpleasant consequences. However, casts will rarely remedy this in a safe
manner since unsigned to signed conversion where the value is outside the
range of the target type is unspecified by the C standard.

~~~
pietrofmaggi
Now with a bit more of time, just for sake of completeness (from the ARM's
System Developers Guide).

"If your code uses addition, subtraction, and multiplication then there's no
performance difference between signed and unsigned operation. However, there
is a difference when it comes to division."

Consider the following short example that averages two integers:

    
    
      int average_v1(int a, int b)
      {
        return (a+b)/2;
      }
    

This compiles to:

    
    
      average_v1
        ADD r0, r0, r1            ; r0 = a+ b
        ADD r0, r0, r0, LSR #31   ; if (r0<0) r0++
        MOV r0, r0, ASR #1        ; r0 = r0 >> 1
        MOV ro, r14               ; return ro
    

Notice that the compiler adds one to the sum before shifting by right if the
sum is negative. In other words it replaces x/2 by the statement:

    
    
      (x<0)?((x+1)>>1):(x>>1)
    

It must do this because x is signed. In C on an ARM target, a divide by two is
not a right shift if x is negative. For example, -3 >> 1 = -2 but -3/2 = -1.
Division rounds towards zero, but arithmetic right shift rounds towards -inf.

It is more efficient to use unsigned types for division. The compiler converts
unsigned power of two divisions directly to right shifts.

For this and other fancy ARM insight take a look at the ARM System Developer's
Guide, really a nice book:
[http://www.elsevier.com/wps/find/bookdescription.cws_home/70...](http://www.elsevier.com/wps/find/bookdescription.cws_home/702211/description#description)

~~~
mansr
This is not specific to ARM. There is to my knowledge no CPU architecture
where an arithmetic right shift works differently.

Unsigned types allow the compiler to perform this optimisation. However,
unsigned types can easily introduce unexpected behaviours elsewhere. One of
the more common is a comparison in which an unsigned wraparound where a
negative result was expected causes the wrong branch to be taken.

If a value is known to be positive, one can always safely use a right shift
directly rather than the division operator.

------
junkbit
I saw the sign and it opened up my mind

