《小菜狗 C 语言入门 + 进阶笔记》(5.1)数据类型 - 强制类型转换

​​​​​​​​​​​​​​​​​​​​文章目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介

1、强制类型转换引入

强制类型转换是把变量从一种类型转换为另一种数据类型。

  • C 语言中如果一个表达式中含有不同类型的常量和变量,在计算时,会将它们自动转换为同一种类型;
  • 在 C 语言中也可以对数据类型进行强制转换;

您可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型,强制类型转换形式如下所示:

(类型说明符)(表达式)

(type_name) expression

2、数据类型转换实例

使用强制类型转换运算符把一个整数变量除以另一个整数变量,得到一个浮点数:

#include <stdio.h>
 
int main()
{
    int sum = 17, count = 5;
    double mean;

    mean = (double) sum / count;
    printf("Value of mean : %f\n", mean );

    return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of mean : 3.400000

这里要注意的是:

强制类型转换运算符的优先级大于除法,因此 sum 的值首先被转换为 double 型,然后除以 count,得到一个类型为 double 的值。

类型转换可以是隐式的,由编译器自动执行,也可以是显式的,通过使用强制类型转换运算符来指定。在编程时,有需要类型转换的时候都用上强制类型转换运算符,是一种良好的编程习惯。

3、整数提升

整数提升是指把小于 intunsigned int 的整数类型转换为 intunsigned int 的过程。

请看下面的实例,在 int 中添加一个字符:

#include <stdio.h>
 
int main()
{
    int  i = 17;
    char c = 'c'; /* ascii 值是 99 */
    int sum;

    sum = i + c;
    printf("Value of sum : %d\n", sum );

    return 0; 
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of sum : 116

在这里,sum 的值为 116,因为编译器进行了整数提升,在执行实际加法运算时,把 ‘c’ 的值转换为对应的 ascii 值。

4、常用的算术转换

常用的算术转换是隐式地把值强制转换为相同的类型。

编译器首先执行整数提升,如果操作数类型不同,则它们会被转换为下列层次中出现的最高层次的类型:
在这里插入图片描述

常用的算术转换不适用于赋值运算符、逻辑运算符 && 和 ||。让我们看看下面的实例来理解这个概念:

#include <stdio.h>
 
int main()
{
    int  i = 17;
    char c = 'c'; /* ascii 值是 99 */
    float sum;

    sum = i + c;
    printf("Value of sum : %f\n", sum );

    return 0; 
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of sum : 116.000000

在这里,c 首先被转换为整数,但是由于最后的值是 float 型的,所以会应用常用的算术转换,编译器会把 i 和 c 转换为浮点型,并把它们相加得到一个浮点数。

而且为了提高效率,C 语言对于不同的两个类型将直接转换成较高类型计算。

举个例子:

对于已经分别被定义且被赋值,类型为 doubleintab

假设如果进行 a + b 运算,那么 b 将直接被隐式转换为 double 类型,然后再进行运算,不能理解为逐层转换(即不能理解为 b 先转换为 unsigned int 类型,再转换为 long => unsigned long => long long => unsigned long long => float => double 类型,最后再进行运算)。

p.s: 说到运算,对于 charshort 类型,进行运算时将会被隐式转换为 int,看代码:

#include <stdio.h>

int main() {
  char c = 22, ch = 33;
  short m = 23, n = 32;
  printf("%d\n", sizeof(c + ch));  //char和char类型的运算
  printf("%d\n", sizeof(m + n));   //short和short类型的运算
  printf("%d", sizeof(m + ch));    //short和char类型的运算
  return 0;
}

输出:

4
4
4

5、补充转换规则

5.1、float、double、long double 类型赋值给整数类型:直接截断小数

如:

#include <stdio.h>

int main() {
  float a = 3.8;
  int b = a;  //进行了一次隐式类型转换
  printf("a=%.2f; b=%d", a, b);
  return 0;
}

根据转换规则和隐式类型转换规则,输出的结果为:

a=3.80; b=3
5.2、整数类型赋值给浮点数(float、double、long double)类型:补足有效小数位

对上述代码进行修改:

#include <stdio.h>

int main() {
  int a = 8;
  float b = a;  //进行了一次隐式类型转换
  printf("a=%d; b=%f", a, b);
  return 0;
}

输出:

a=8; b=8.000000  //%f默认输出6位小数
5.3、存储长度较短的类型赋值给存储长度较长的类型:补足有效位,其它位补 0

假设有如下定义:

char c = 56;
short num = 67;
int m;
long long int n;

如果执行以下操作:

m = ((int)c);
n = ((long long)num);

那么它们在内存以 2 进制格式分别存储为:

                                                               00111000  //Binary of 'c'
                                                      00000000 01000011  //Binary of 'num'
                                    00000000 00000000 00000000 00111000  //Binary of 'm'
00000000 00000000 00000000 00000000 00000000 00000000 00000000 01000011  //Binary of 'n'
5.4、存储长度较长的类型赋值给存储长度较短的类型:舍弃高位(但保留符号),截断低字节给存储长度较短的类型

假设定义:

long long int l = 223372036854775807;

进行赋值:

int i = (int)l;

它们在内存以 2 进制格式分别存储为:

00000011 00011001 10010011 10101111 00011101 01111011 11111111 11111111  //Binary of 'l'
                                    00011101 01111011 11111111 11111111  //Binary of 'v'

p.s: 此时的 v=494665727。

顺带说明一下,如果变量 “l” 的后 32 个字节都为 1,那么 v 将等于 -1。

5.5、unsigned 类型赋值给非 unsigned 类型:直接传递数值

**注意:**如果 unsigned 类型储存的量太大,强制类型转换后可能会出现非 unsigned 类型的值的绝对值不等于 unsigned 类型的值的绝对值的情况。

说到 “unsigned 类型储存的量太大”,顺带说一下,虽然 printf 输出 int 和 unsigned int 时可以混用 %d(或%i)和 %u(或%ui),但还是建议输出 int 类型的时候用 %d(或%i),输出 unsigned int 类型时用 %u(或%ui)(其它类型同理<如%ul 等>)

看一个例子:

#include <stdio.h>

int main() {
  unsigned int x = 4294967295;  //这个数字为(2^32)-1, 而int类型最大存储数字的值为(2^31)-1
  int y = ((int)x);
  printf("signed of x=%d", x);  //这里有一次隐式类型转换(unsigned int => int)
  putchar('\n');
  printf("unsigned of x=%u\n", x);
  printf("signed of y=%d", y);
  return 0;
}

可是因为隐式类型转换,结果输出为:

-1
4294967295
-1

出现“-1”的这个输出就是因为“unsigned 类型储存的量太大(大于了同类型但非 unsigned 的类型)”

p.s: 不一定都为 -1,具体要看 unsigned 类型的值的 2 进制

5.6、非 unsigned 类型赋值给 unsigned 类型:直接传递数值

给个小技巧:如果你想“临时”给一个不知道正负的非 unsigned 类型的变量加上绝对值,可以使用 abs 函数,但利用(unsigned)(非 unsigned 类型变量名)可以节省一点内存开销

但是也有弊端:可能会出现 unsigned-unsigned 永远大于 0 的情况(不确定)

最后补充一下,强制类型转换只是临时类型转换,并不影响变量本身储存的值,看如下代码:

#include <stdio.h>
int main() {
  float a = 6.9;
  printf("%.3f", a);
  putchar('\n');
  ((int)a);
  printf("%.3f", a);
  return 0;
}

输出结果:

6.900
6.900

每日一更!

公众号、优快云等博客:小菜狗编程笔记

谢谢点赞关注哈!目前在飞书持续优化更新~

日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小菜狗编程笔记

你的鼓励将是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值