无符号数溢出判断,返回值要求全一

是一个面试题,让我写一个函数,函数的参数定义为无符号整形,让我判断溢出,溢出返回全一,无溢出则进行函数要求。怎么判断无符号的溢出和返回值为全1啊。

如果是相加,可以利用a+b<a判断溢出,如果a+b<a为真,则溢出,反之则未溢出。
如果是相乘,可以根据a和b的最高位位数判断,例如a=b=65536都是4字节,用二进制表示为1 0000 0000 0000 0000,最高位为16位(从0开始数),16加16等于32大于4字节的最高位31位,必然溢出;如果相加小于30位,则必然不溢出;如果相加等于31位,则将a一个最高位和剩余部分分别与b相乘,再利用加法判断是否溢出。由于最高位与b相乘时不会进位,因此不会溢出;而剩余部分的最高位位数与b的最高位位数相加等于30,也不会溢出,所以不会误判。

#include<stdio.h>

typedef enum{
    FALSE,TRUE
}BOOL;

int gethighestbitnum(unsigned int a) {
    int r = -1;
    while (a > 0) {
        a >>= 1;
        r++;
    }
    return r;
}

BOOL plus_overflow(unsigned int a, unsigned int b) {
    return a + b < a;
}

BOOL multiply_overflow(unsigned int a, unsigned int b) {
    unsigned int temp;
    int l1, l2, lmax = 8 * sizeof(unsigned int) -1;
    l1 = gethighestbitnum(a);
    l2 = gethighestbitnum(b);
    if (l1 + l2 > lmax) {
        return TRUE;
    } else if (l1 + l2 < lmax) {
        return FALSE;
    } else {
        temp = b << l1; //b与a最高位取出来相乘
        a = a & ~(1 << l1); //a去掉最高位
        a = a * b;
        return temp + a < temp;
    }
}

int main() {
    unsigned int a, b, max = -1;
    
    printf("请输入两个小于%u的非负加数:\n", max);
    scanf("%u%u", &a, &b);
    if (plus_overflow(a, b))
        printf("加法溢出了!\n");
    else 
        printf("%u + %u = %u\n",a,b, a + b);
        
    printf("请输入两个小于%u的非负乘数:\n", max);
    scanf("%u%u", &a, &b);
    if(multiply_overflow(a,b))
        printf("乘法溢出了!\n");
    else 
        printf("%u * %u = %u\n",a,b, a * b);
    return 0;
}

img

img

一般来说,当无符号整型变量的值超过了其数据类型所能表示的最大值时,就会发生溢出。

具体地,如果一个无符号整型变量的值为 n,数据类型的位数为 k,则它能表示的最大值为 2^k - 1。因此,当 n > 2^k - 1 时,就发生了溢出。