Search code examples
c16-bitinteger-arithmeticinteger-promotion

8051 16 bit addition/multiplication result 16 bit instead of 32 bit


I have a problem. In this program the variable x should be set to 0x10000 but in both operations the result is 0.

This is not the main program but a test to find the reason for the error. I am currently making a 64 bit multiplier with hex input. I used 16-bit multiplication using Keil and Proteus

int main() {
    unsigned long int x = 0;
    x = 0x8000 * 0x2;
    x = 0x8000 + 0x8000;
    return 0;
}

Solution

  • The literal 0x8000 is of type unsigned int. On your 16-bit machine, the int and therefore unsigned int is of the natural size of 16 bits, the smallest accepted by the C standard. The integer promotion rules say that the smaller width types are widened to int or unsigned int, but no further (C11 n1570 6.3.1.1p2):

    If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. 58) All other types are unchanged by the integer promotions.

    An operand is widened from int or unsigned int only if the other operand has a greater rank.

    Here, 0x8000 + 0x8000 is calculated using unsigned int which will wrap to 0, because the maximum value that can be represented in unsigned int is 0xFFFF.

    You should force at least one of the operands to unsigned long using either the suffix UL, or by adding an explicit cast:

    int main() {
        unsigned long int x=0;
        /* unsigned long int * int */
        x = 0x8000UL * 0x2;
    
        /* unsigned long + unsigned int */
        x = (unsigned long)0x8000 + 0x8000;
        return 0;
    }
    

    See also In a C expression where unsigned int and signed int are present, which type will be promoted to what type? for general discussion.