C++ 实战之强制转换和自动类型提升

1,025 阅读3分钟

何时需要强制转换?何时又不需要?下面我们一起对比一下下面两处代码

long lastNum = (long)INT_MIN-1;

int curNum = 5if(curNum <= lastNum)
{
    ...
}

【知识点补充】

首先补充一个小知识点。 32位系统中 int 类型的最大值 INT_MAX 和最小值 INT_MIN,以及它们的计算方式。下面是一个简单的表格:

名称计算方式
INT_MAX21474836472^31 - 1
INT_MIN-2147483648-2^31

其中INT_MAX:在32位有符号整数中,最高位(符号位)为0,表示正数,其余的所有位都为1时,表示的是最大的正数。因此,最大值是 2^31 - 1【具体应用等比数列求和公式:1 * 2^0 + 1 * 2^1+ ... + 1 * 2^30=(1-2^31)/(1-2)=2^31-1】即2147483647。

INT_MIN:在32位有符号整数中,最高位(符号位)为1,表示负数,其余位都为0表示的是最小的负数。因此,最小值是 -2^31 = -2147483648。

【解惑】

下面我们一起来思考一下。为什么第一处这里需要强制转换?而比较的时候curNum <= lastNum 不需要强制转换呢,这是c++的什么用法?

在C++中,INT_MIN 是 int 类型能够表示的最小值。在标准中,这个值是一个负数。当你尝试对一个负数 INT_MIN 进行减法操作时,如果直接将其作为 int 类型处理,可能会遇到整数溢出的问题,因为 int 类型的最小值再减去一个正数会导致数值无法在 int 类型的范围内表示。

这就是为什么在初始化 lastNum 时需要进行强制类型转换 (long)INT_MIN,将 INT_MIN 转换为 long 类型,这样 lastNum 就有足够的空间来存储减去 1 之后的值,而不会发生溢出。

在比较 node->val <= lastNum 时,由于 lastNum 已经是 long 类型,而 node->val 是 int 类型,C++ 会自动进行类型提升(type promotion),将 int 类型的 node->val 提升到 long 类型后再进行比较。这种类型提升是安全的,因为 int 类型的值总是能够无损地转换为 long 类型。

总结来说,这里的强制类型转换是为了避免初始化时的整数溢出,而在比较时的自动类型提升则是 C++ 的类型转换规则所允许的。

int a;
int b;
int res = (a + b)/2;

在实际应用中有这样一种场景我们经常容易忽略,也就是两个int相加,需要考虑int的范围,如果int是0 - 2 ^ 31 - 1,那么两个int相加就会发生溢出的情况,所以这种情况,我们就要注意考虑将代码改成如下:

#include <iostream>

int main() {
    int a = 2147483647;    // int的最大值
    int b = 1;             // 添加的值
    long long res;         // 使用long long来存储可能的大结果

    res = ((long long)a + b)/2;  // 将至少一个操作数转换为long long

    std::cout<< res << std::endl;

    return 0;
}

在这个示例中,将a强制转换为long long类型来确保加法操作不会溢出。如果b也是一个很大的值,你也需要将它转换为long long,但由于前提限制了a、b的范围,所以这里就不用将b转换了。这样,结果res就会存储在long long变量中,从而避免了溢出问题。