C语言中的整型提升与混合类型数据的运算

C中会根据操作数的不同,某些运算符会 引起操作数的值从一种类型转换为另一种类型。

一.关于整型提升

先看一段代码请问输出的值是多少?

<span style="font-size:14px;">    char a = 1;
    char b = 2;
    char c = 0;
    c = a + b;
    printf ("the size of the result of a+b :%lu\n" ,sizeof(a+b) );
    printf ("the size of the result of c :%lu\n" ,sizeof(c) );</span>

1. C语言之父的著作 K&R 中关于整型提升(integral promotion)的定义为:

"A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion."

归纳总结为两个原则如下:

1. 一个表达式中凡是可以使用整型的地方,都可以使用char、short int 或者整型位域(这几个基本类型无论是否带符号都可)的变量,以及枚举类型的对象。

 2). 如果1)中的变量的原始类型的所有值都可以被int表示(没有造成值的丢失,就比如这种unsigned short提升为int的情况),那么原值被转换为int; 否则的话,转为unsigned int型。


经过对以上知识的理解,不难得到正确的答案,由于a+b是一个表达式,且都为char型,符合整型提升的条件,所以需对a和b进行整型提升,然后执行“+”运算,计算结果(int型)再赋值给c(char型),又执行了隐式的类型转换。由于int型可以表示char的整个值域 -128-127,所以提升为int型,结果是4byte,但是 c不是表达式不符合整型提升的条件不会进行提升还是1byte.

上段代码运行结果:

the size of the result of a+b :4 

the size of the result of c :1

二.算数类型转换:

不同类型数据之间进行算数运算时,会将所有操作数转换为同种类型,并以此作为结果的类型,这种方式称为普通算术类型的转换。根据K&R中描述的具体转换规则:

首先,如果参与运算的任何一个操作数为long double类型,则将另一个操作数转换为long double类型。

否则,如果,任何一个操作数为double类型,则将另一个操作数转换为 double类型。

否则,如果,任何一个操作数为float类型,则将另一个操作数转换为 float类型。

否则,同时对两个操作数进行整型提升,

然后,如果,任何一个操作数为unsigned long int 类型,则将另一个操作数转换为 unsigned long int 类型。

否则,如果,一个操作数long int 另一个为unsigned int 类型则结果依赖于long int类型能否表示所有的unsigned int ;

   如果可以则将unsigned int类型转换long int(64位系统下long是8byte 可以表示unsigned int 但是32位环境不可以表示)

   如果不可以,则将两个数都转为unsigned long int 

否则,如果,任何一个操作数为long int 类型,则将另一个操作数转换为 long int 类型。

否则,如果,任何一个操作数为unsigned int 类型,则将另一个操作数转换为 unsigned  int 类型。

否则,将两个数都转换为int型

总结:普通算术类型转换只在在操作数之间类型不一致的情况下发生,整型提升在操作数具有相同的类型时,仍有可能发生整型提升,比如两个char型运算。

看下面代码,输出什么?

    int a = -1;
    unsigned int b = 1;
    if (a > b)
        printf("a > b\n");
    else
        printf("a < b\n");
由于运算的两个数据类型不一样,需要进行算术类型的转换,根据上面的规则将int转换为 unsigned int ,根据上篇文章中讲到的数据编码知识有,-1是有符号的int型按照补码方式编码 为:0x ffff ffff ,表示的具体值为 -1*2^31+1*2^30+...+1*2^0 = -1,转换为无符号的就是当做原码处理认为无符号位,表示的值为1*2^31+...+1*2^0 = 4294967295即无符号的最大值,所以结果为a > b;

再看一个表达式

表达式 (unsigned short)1 > -1 的值是0还是1

答案是1,在这个问题中,其实比较的是两个signed类型的值。这是因为C在执行比较操作前,会将两个操作数“提升”为int型。那为什么不是做基本数据类型的转换,将-1转为unsigned类型呢,如果是这样-1会变成很大的数结果就是0了,原因是:K&R中关于基本算数类型的转换已经说的很清晰了见上文蓝色字体部分,没有float或double的先都来一次整型提升,由于int型能表示short所以提升为signed int 提升之后还是1;

最后来看一个表达式:

表达式 -1L > 1U 在64位环境下的值是? 在 32位环境下的值是?
A. 在两种平台下均为0
B. 在两种平台下均为1
C. 在 x86-64 平台下为0, 在 x86 平台下为1
D. 在 x86-64 平台下为1, 在 x86 平台下为0

由与运算的两个数据类型不一样,需要做基本数据类型的转换由于64位环境下long int 8byte (不知道的见上篇文章)而unsigned int 4byte 都转为long int型,值都不变,结果为0,32位环境下long int 4 byte相当于int  而 unsigned int 4byte ,由上文绿色字体部分,long int 不能表示所有的unsigned int所以转为 unsigned int比较 -1 转为无符号的最大值 ,结果为1;

答案:C

三. C中的常量的复习

先看几行代码,下面代码中的数字1099511627775 = 0xFF FFFF FFFF:

    char *pC = "hello ";
    printf("sizeof(pC) = %lu\n",sizeof(pC));
    printf("sizeof(*pC) = %lu\n",sizeof(*pC));
    
    printf("sizeof(-1) = %lu\n",sizeof(-1));
    printf("sizeof(-1099511627775) = %lu\n",sizeof(-1099511627775));
    printf("sizeof(100U) = %lu\n",sizeof(100U));
    printf("sizeof(100UL) = %lu\n",sizeof(100UL));
    
    printf("sizeof(1099511627775) = %lu\n",sizeof(1099511627775));
    printf("sizeof(1099511627775U) = %lu\n",sizeof(1099511627775));
    
    printf("sizeof('A') = %lu\n",sizeof('A'));
    printf("sizeof(\"abcde\") = %lu\n",sizeof("abc"));

上面代码都是和常量相关的,复习一下

1.整型常量,由一串数字组成 如 1,100,-123,等

2.实型常量 如 0.45, 12.34E3(12.34*10^3)

3.字符常量,又分为两种

1)普通字符常量 如‘A’,'b'

2)转义字符常量‘\'’

4.字符串常量 "hello c"

在此想要说明的问题是上面说明的几种常量是默认什么基本数据类型,占用几个字节存储,运算是如何转换呢?

通过对K&R的研读及做了一些测试,现总结如下:

整型常量的类型同它的形式、值、后缀有关;

整型常量若以

1.字母u或U为后缀,表示一个无符号型, 可能为unsigned int 或unsigned long int 具体看值的大小,默认为unsigned int

2.若以,字母l或L为后缀,表示一个长整型数,可能为 long int 或unsigned long int

3.若以,字母UL为后缀,则是无符号长整形 unsigned long int

4.如果没有后缀,且是十进制,可能为 int ,long int,unsigned long int 如果int可以表示默认为int 型 

4.如果没有后缀,且是八进制十六进制,可能为 int ,unsigned int ,long int,unsigned long int 如果int可以表示默认为int 型 

浮点常量

浮点常量的值与后缀有关

若以字母f或F为后缀表示float型

若以字母l或Lwei为后缀表示long double 型

没有后缀则默认为double

字符常量

字符常量在计算机存储的形式是它的ASCLL值,如’a‘对应97,所以字符常量’a‘相当于97为int型,会占用4byte存储,并不是char型

上面代码在64位环境下的运行结果为:

sizeof(pC) = 8

sizeof(*pC) = 1

sizeof(-1) = 4

sizeof(-1099511627775) = 8

sizeof(100U) = 4

sizeof(100UL) = 8

sizeof(1099511627775) = 8

sizeof(1099511627775U) = 8

sizeof('A') = 4

sizeof("abcde") = 6 //算上最后的'\0'


posted @ 2015-04-02 17:17  HugoJiang  阅读(2737)  评论(0编辑  收藏  举报