一、自动类型转换

1.1 先看一个选择题

int main(void)
{
    unsigned int a = 100;

    while(a>-1)
    {
        --a;
    }

    printf("%d\n", a);

    return 0;
}

pritnf打印的结果是多?

A -1   B 100    C 0   D 死循环

这道题的正确答案是B,那么为什么选B呢?

这道题的实际情况是,条件a > -1根本不成立,while循环不会进去,所以a的值任然还是100

很多同学可能都做错了,做错的原因就是因为对“自动类型转换”不理解而导致的,
接下来我们就来详细的讲一讲“自动类型转换”是个啥,为什么条件a > -1根本就不会成立,
“自动类型转换”对a > -1到底有什么影响


二、回顾“强制类型转换”

强制类型转换分为两种,一种是“隐式强制类型转换”,另一种是“显示强制类型转换”使用

(1)什么时候会使用“隐式强制类型转换”

  • 使用=来初始化和赋值时,当左值类型与右值类型不一致时
  • 进行函数传参,当实参与形参的类型不一致时
  • 函数返回“返回值”,当返回值与返回类型不一致时

一般来说我们不建议进行“隐式强制类型转换”,
因为可能会导致很多的警告,我们都建议进行明确的“显示强制类型转换”

(2)自动类型转换
本小节要介绍的“自动类型转换”,虽然也是类型之间的转换,但是与“强制类型转换”并不一样


三、进行算数、关系、位运算时的自动类型转换

在进行算数、关系、位运算时,“运算数”的类型不可能完全相同,进行运算时必须转换为同一类型后才能运算

比如:

char a  = 'a';
short b = 20;
int c   = 10;

a * b + c; //a b c的类型不一致,进行算数运算时,必须进行类型统一后才能运算
if(a > c)  //a c的类不一致,进行关系运算时,同样也需要进行类型统一后才能运算

像例子中这种进行类型统一的类型转换,就是自动类型转换。自动类型转换顾名思义,就是自动完成的


四、自动类型转换的规则

  1. 总体原则:低类型向高类型转换、有符号向无符号转换
    char、short————>int————>unsigned int————>long————>unsigned long————>double
                                                                        ^
                                                                        |
                                                                      float
    
  2. 当有charshort参与运算时,会先自动转为int,然后再参与运算
  3. 当有浮点参与运算时,所有类型都会自动转成double,然后参与运算

仅仅看三条规则,估计大家看不懂是什么意思,不过没关系,我们介绍完后面的例子后,大家自然就能理解了

例子0

char a  = 20;
short b = 30;
char c;

c = a + b;

achar————>intbshort————>int,然后再相加,a + b相加后结果的类型为int赋值给c时,
再将int隐式强制转换为char,然后再赋值给c


例子1

char a  ='a';
short i = 1;
long  k = 20;
float f = 23.1;
int result;

result=(a / i + k) + (f * a - i);

1)(a/i+k)
(a)a/iaicharshort———>int,然后相除,a/i的结果为int
(b)a/i+ka/i的结果为intklong,因此a/i结果会从int———>long后,再与k相加,因此(a/i+k)结果就为long

2)(f*a-i)
(a)f*a
a————>int
ffloat,有浮点参与运算,因此f、a————>double,然后再相乘,相乘的结果为double

(c)f*a-i
ishort——>int
f*a的结果为double,所以i又从int————>double,然后再相减

(f*a-i)结果的类型最后就为double

3)(a/i+k)(f*a-i)相加
(a/i+k)的结果为long(f*a-i)的结果为double,所以前者从long————>double后,然就再相加

(a/i+k)+(f*a-i)的结果为double,再隐式强制转换为int,然后赋值给result


例子2

char a  ='a';
short i = 1;
unsigned int d = 20;
long int k = 20;
unsigned long int f = 304;
char result;

result = a*i*d + k + f + 12.3;

1)a*i*d
aichar、short———>int,然后相乘,a*i的类型为int
dunsigned inta*i———>unsigned int,然后与d相乘

2)a*i*d + k
a*i*dunsigned intklonga*i*d————>long,然后与k相加

3)a*i*d +k + f
a*i*d + klong类型,funsigned longa*i*d+k ————> unsigned long,然后相加

4)a*i*d +k + f + 12.3
a*i*d +k + funsigned long,常数12.3doublea*i*d+k+f————>double,然后再与12.3相加

最后整个的结果为double,赋值给result时,会隐式强制转换为char


例子3

char a=10;
short b=20;

if(a > b)
{

}

a、b————>int,然后进行比较


例子4

unsigned int a = 100;

while(a>-1)
{
    --a;
}

printf("%d\n", a);

这个就是前面的那个例子

-1的类型默认为int,在计算机中存储时存储的是补码

         取反  +  1                  -1的补码
|-1| ————————————————————> 11111111 11111111 11111111 11111111

由于a的类型为unsigned int,而-1的类型为int,根据自动类型转换规则,
-1的类型会从int转换unsigned int,因此会以unsigned int来解释
11111111 11111111 11111111 11111111,最高位不再是符号位,

此时11111111 11111111 11111111 11111111为正数的补码,由于正数的补码就是本身,
因此代表的是一个非常大的正数4294967295

while(a>-1) 其实为 while(a>4294967295)

因此不条件不成立,根本不会进入while循环,因此a的值还是100,所以打印结果100

注意:
1)表达式中的整数比如-1,默认为int
例外:123L,这个表示longLlong的意思

2)表达中的浮点数比如12.45,默认为double

int a = 10;
a + 12.45; //a从int————>double,然后与12.45相加

例外:12.45f,表示为float型,f就是float的意思


例子5

& | ~的位运算中,同样会涉及到自动类型转换的问题,到下一章讲“位操作”时我们再介绍


五、自动类型转换陷阱

前面的while(a > -1),按照正常的逻辑思维来说,肯定是希望进入while循环的,
但是最终因为“自动类型转换”导致了条件的不成立,
这种因为“自动类型转换”而导致的问题,我们就常称为“自动类型转换陷阱”

我们这里再看一个例子:

unsigned int a = 6;

int b = -10;

if( (a + b) > 6)
{
    printf(" > \n");
}
else
{
    printf(" < \n");
}

一般理解:(a+b) > 66 + -10 > 6,条件不成立,执行else中得printf语句 <
但是实际情况是:
b中存储-6时,存储的是补码。

        取反 +1
|-6|————————————————> 111111111 11111111 11111111 11110101

a的类型为unsigned int,而bint,根据自动类型转换的规则,b会用从int变为unsigned int
此时b111111111 11111111 11111111 11110101不在表示-6,而是一个非常大的数4294967285
因此(a+b) > 6成立,输出结果为 >


六、 强制类型转换 与 自动类型转换 的区别

不管是隐式强制类型转换,还是显式强制类型转换,在大部分类型之间都可以进行强制类型转换,
不过将高类型转为低类型时,往往可能会丢失数据

int a =3435345345;
char b = a; //会丢失“高三个字节”的数据

自动类型转换

char、short————>int————>unsigned int————>long————>unsigned long————>double
                                                                      ^
                                                                      |
                                                                    float

我们从自动类型转换的规则可以的看出,自动类型的最大特点为,
转换方向是从低类型向高类型转换,保证不会丢失数据

就算是int ————> 转为unsigned int,顶多就是解释方式变化了,但是空间中所放的二进制数并没有变化

在有些书上,往往会将“隐式强制转换” 也归类为“自动类型转换”的一种,但是我们这边不这么归类,
因为通过前面的描述可以看出,“强制类型转换“和“自动类型转换”还是着明显区别的