当前位置: 首页 > article >正文

C语言:整型提升

一, 整型提升

C语⾔中整型算术运算总是⾄少以缺省(默认)整型类型的精度来进⾏的。
为了获得这个精度,表达式中的字符和短整型操作数在使⽤之前被转换为普通整型,这种转换称为整型提升
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执⾏,CPU内整型运算器(ALU)的操作数的字节⻓度⼀般就是int的字节⻓度,同时也是CPU的通⽤寄存器的⻓度。
因此,即使两个char类型的相加,在CPU执⾏时实际上也要先转换为CPU内整型操作数的标准⻓
度。
通⽤CPU(general-purpose CPU)是难以直接实现两个8⽐特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种⻓度可能⼩于int⻓度的整型值,都必须先转换为 int或unsigned int,然后才能送⼊CPU去执⾏运算

整型提升的规则

  • 有符号类型:如果原类型是有符号类型(如 signed charsigned short),则将其值符号扩展为 int 类型。也就是说,如果原类型的最高位(符号位)是 1,则在扩展后的 int 类型中,高位全部补 1;如果最高位是 0,则高位全部补 0。
  • 无符号类型:如果原类型是无符号类型(如 unsigned charunsigned short),则将其值零扩展为 int 类型,即高位全部补 0。

整型提升的原因

  • 提高计算效率:大多数计算机的 CPU 对于 int 类型的运算处理速度更快,将小整数类型提升为 int 类型可以利用 CPU 对 int 运算的优化,提高计算效率。
  • 统一运算操作数类型:在表达式求值时,要求运算符的操作数类型一致。通过整型提升,可以将不同的小整数类型统一转换为 int 类型,便于进行运算。

整型提升的示例

示例 1:有符号类型的整型提升
#include <stdio.h>

int main() {                                  //          10000001(原码)
                                              //          11111111(反码)
    signed char a = -1;  // 有符号字符型,8 位,二进制表示为 11111111(补码,只取八位比特)
    int result = a + 2;  // 进行加法运算,a 会被提升为 int 类型

    // 有符号字符型 -1 提升为 int 类型后,二进制表示为 11111111 11111111 11111111 11111111
    //2的二进制表示00000000 00000000 00000000 00000010(补码)
    //提升后:-1+2=00000000 00000000 00000000 00000001(补码)  
    printf("结果: %d\n", result);
    return 0;
}

在这个例子中,signed char 类型的变量 a 的值为 -1,其 8 位二进制表示是 11111111。在进行 a + 2 运算时,a 会被提升为 int 类型,通过符号扩展,其 32 位二进制表示变为 11111111 11111111 11111111 11111111。然后与 2(二进制 00000000 00000000 00000000 00000010)相加,得到结果 1

示例 2:无符号类型的整型提升
#include <stdio.h>

int main() {
    unsigned char b = 255;  // 无符号字符型,8 位,二进制表示为 11111111(补码)
    int result = b + 1;     // 进行加法运算,b 会被提升为 int 类型

// 无符号字符型 255 提升为 int 类型后,二进制表示为 00000000 00000000 00000000 11111111(补码)
    // 与 1 相加后结果为 256,二进制表示为 00000000 00000000 00000001 00000000(补码)
    printf("结果: %d\n", result);
    return 0;
}

这里 unsigned char 类型的变量 b 的值为 255,其 8 位二进制表示是 11111111。在进行 b + 1 运算时,b 会被提升为 int 类型,通过零扩展,其 32 位二进制表示变为 00000000 00000000 00000000 11111111。然后与 1(二进制 00000000 00000000 00000000 00000001)相加,得到结果 256

注意事项

  • 对表达式结果的影响:整型提升可能会影响表达式的计算结果,特别是在涉及有符号和无符号类型混合运算时。例如:
    #include <stdio.h>
    
    int main() {
        signed char a = -1;
        unsigned char b = 255;
        int result = a + b;
    
        // a 提升为 int 类型后是负数,b 提升为 int 类型后是正数
        // 相加结果为 254
        printf("结果: %d\n", result);
        return 0;
    }

    在这个例子中,signed char 类型的 a 提升为 int 类型后是负数,unsigned char 类型的 b 提升为 int 类型后是正数,它们相加的结果是 254

  • 位运算中的整型提升:在进行位运算(如按位与 &、按位或 | 等)时,也会进行整型提升。例如:
    #include <stdio.h>
    
    int main()
     {
        unsigned char x = 0xFF;
        unsigned char y = 0x01;
        unsigned char result = x & y;
    
        // x 和 y 先提升为 int 类型进行位与运算,结果再截断为 unsigned char 类型
        printf("结果: %d\n", result);
        return 0;
    }

    算术转换

  • 如果某个操作符的各个操作数属于不同的类型,那么除⾮其中⼀个操作数的转换为另⼀个操作数的类型,否则操作就⽆法进⾏。下⾯的层次体系称为寻常算术转换。

算术转换的规则

      算术转换遵循以下一般规则,这些规则按照优先级从高到低的顺序执行:

  • 长双精度扩展:如果其中一个操作数是 long double 类型,那么另一个操作数会被转换为 long double 类型。
  • 双精度扩展:如果其中一个操作数是 double 类型,而另一个不是 long double 类型,那么另一个操作数会被转换为 double 类型。
  • 单精度扩展:如果其中一个操作数是 float 类型,而另一个不是 double 或 long double 类型,那么另一个操作数会被转换为 float 类型。
  • 整型提升:如果操作数不属于上述浮点类型,那么会先对操作数进行整型提升(将比 int 小的整数类型转换为 int 或 unsigned int)。
  • 整数类型转换:经过整型提升后,如果两个操作数的类型仍然不同,会将较低等级的整数类型转换为较高等级的整数类型。整数类型的等级从低到高大致为:charshortintunsigned intlongunsigned longlong longunsigned long long

算术转换的原因:

  • 统一操作数类型:C 语言的二元运算符通常要求两个操作数的类型相同,算术转换可以将不同类型的操作数转换为相同类型,使得运算符能够正确执行。
  • 保证计算精度:在进行混合类型的算术运算时,将操作数转换为较高精度的类型可以避免数据丢失,保证计算结果的准确性。

算术转换的示例

示例 1:浮点类型的算术转换
#include <stdio.h>

int main() 
{
    float f = 3.5f;
    double d = 2.0;
    // f 会被转换为 double 类型进行计算
    double result = f + d;
    printf("结果: %lf\n", result);
    return 0;
}

 在这个例子中,由于 d 是 double 类型,f 是 float 类型,根据规则,f 会被转换为 double 类型,然后进行加法运算。

示例 2:整数类型的算术转换
#include <stdio.h>

int main()
 {
    char c = 'A';  // ASCII 码值为 65
    int i = 10;
    // c 会先进行整型提升为 int 类型,然后进行加法运算
    int result = c + i;
    printf("结果: %d\n", result);
    return 0;
}

     这里 c 是 char 类型,i 是 int 类型,c 会先进行整型提升为 int 类型,然后与 i 进行加法运算。          

示例 3:混合类型的算术转换         

#include <stdio.h>

int main() {
    short s = 5;
    float f = 2.5f;
    // s 会先进行整型提升为 int 类型,然后再转换为 float 类型进行计算
    float result = s + f;
    printf("结果: %f\n", result);
    return 0;
}

在这个例子中,s 是 short 类型,f 是 float 类型。s 先进行整型提升为 int 类型,然后根据规则,int 类型的 s 会被转换为 float 类型,再与 f 进行加法运算。

注意事项

  • 数据丢失问题:在进行算术转换时,如果将较高精度的类型转换为较低精度的类型,可能会导致数据丢失。例如:
    #include <stdio.h>
    
    int main() 
    {
        double d = 123456789.123;
        int i = (int)d;  // 强制将 double 类型转换为 int 类型,可能会丢失小数部分
        printf("结果: %d\n", i);
        return 0;
    }

    在这个例子中,将 double 类型的 d 强制转换为 int 类型,小数部分会被截断,可能会导致数据丢失。

  • 无符号类型的影响:当涉及无符号类型和有符号类型的运算时,需要特别注意结果的符号性。例如:
    #include <stdio.h>
    
    int main()
     {
        unsigned int u = 4294967295;  // 无符号整型的最大值
        int i = -1;
        // 由于算术转换,i 会被转换为无符号类型,结果可能不符合预期
        unsigned int result = u + i;
        printf("结果: %u\n", result);
        return 0;
    }

    在这个例子中,i 是有符号 int 类型,u 是无符号 int 类型,在进行加法运算时,i 会被转换为无符号类型,导致结果可能不符合预期。

    理解算术转换规则对于编写正确的 C 语言代码至关重要,特别是在处理混合类型的算术运算时。

                    

 


http://www.kler.cn/a/528627.html

相关文章:

  • 告别复杂,拥抱简洁:用plusDays(7)代替plus(7, ChronoUnit.DAYS)
  • 【实战篇章】深入探讨:服务器如何响应前端请求及后端如何查看前端提交的数据
  • MINIRAG: TOWARDS EXTREMELY SIMPLE RETRIEVAL-AUGMENTED GENERATION论文翻译
  • c++ 定点 new 及其汇编解释
  • 精准化糖尿病知识问答(LLM+机器学习预测模型)
  • Autogen_core源码:_agent_instantiation.py
  • 前端知识速记:节流与防抖
  • Vue2.x简介
  • MongoDB快速上手(包会用)
  • 浅析DDOS攻击及防御策略
  • Linux系统部署Python项目持续运行配置
  • 数据结构【单链表操作大全详解】【c语言版】(只有输入输出为了方便用的c++)
  • LightM-UNet(2024 CVPR)
  • 面试之SolrElasticsearch
  • DRM系列五:注册DRM设备--drm_dev_register
  • C++11新特性之lambda表达式
  • 类和对象(中)---默认函数
  • Linux命令入门
  • Python 模块导入问题终极解决指南
  • 土地覆盖产品批量下载(GLC_FCS30 、Esri_GLC10、 ESA_GLC10 、FROM_GLC10)
  • 深度学习 DAY3:NLP发展史
  • 网络工程师 (11)软件生命周期与开发模型
  • vscode命令面板输入 CMake:build不执行提示输入
  • Mono里运行C#脚本39—mono_jit_runtime_invoke函数
  • mac 手工安装OpenSSL 3.4.0
  • Linux02——Linux的基本命令