warning:implicit conversion loses integer precision:‘int‘ to ‘unsigned short‘ -- C integer promotion

C integer promotion 理解

先看下导致标题报警的代码:

unsigned char addr;
unsigned short buf;

addr = 0x20;

buf = ((unsigned short)addr) << 8;

本意是想将 unsigned char 型的变量先强制转换成 unsigned short 型,然后左移 8bit 再赋值给一个 unsigned short 型的变量。

但这段代码编译时会报标题的警告。一开始怎么也想不明白,整个代码跟警告中的 int 有什么关系,为什么会导致这个 warning?

经过在网上查找,弄明白了原因,是 C integer promotion 的原因。理解 C integer promotion 后发现确实很容易忽略这个问题造成隐藏的错误,就用上例作为说明来记录一下,避免忽视 C integer promotion 引起的问题。

直接分析上例,在 C 语言中,像 char 和 short int 这种字节数小于 1 个字节(4 bytes),即小于 int 字节数的数据类型,在进行运算时,编译器会自动将他们转化成 int 类型,这就是 C integer promotion

原例代码中将 unsigned char 型变量 addr 先强制转化成 unsigned short 型((unsigned short)addr),本意是考虑因为要做左移运算,unsigned char 型只有一个字节,直接做左移运算会不会造成溢出,所以先将 unsigned char 强制转化成 unsigned short 后再左移,并且以为这样操作后,左移完后的数据((unsigned short)addr)也还是 unsigned short 型,就可以赋值给另一个 unsigned short 型变量 buf 了。

但是因为有 C integer promotion 作用,对 unsigned short 型的 addr 做左移运算(<<),这时编译器就会将 addr 转成了 int 型变量。再将 int 型变量 addr 赋值给 unsigned short 型变量 buf,就会触发警报,有将 int 型转成 unsigned short 型丢失精度的风险。

在了解 C integer promotion 后,总结一下上例一开始思路的问题:首先对 unsigned char 型变量 addr 做左移运算,不用担心溢出问题,编译器会自动将 addr 转化成 int 型,所以左移 8 位不会溢出。另外即使做了强制转换 (unsigned short)addr 做左移操作后,编译器还是把 addr 转化成了 int 型,因为 unsigned short 也在 C integer promotion 的范围内,所以此时 addr 还是 int 型,并不是 unsigned short 型,由此会引发了标题的 warning。

如何解决上例的问题,只要将最后一行代码做如下修改就可:

buf = (unsigned short)(addr << 8);

这样,首先将 unsigned char 型变量 addr 左移 8 位(不用担心溢出问题),左移后 addr 会被自动转化为 int 型,即 (addr<<8) 为 int 型,为了将 int 型的 (addr<<8) 赋值给 unsigned short 型变量buf,必须在 (addr<<8) 前面加一个 unsigned short 强制转化,这样就没有问题了。

C integer promotion 注意事项

C integer promotion 什么时候会发生?

只有在对 char,shor int 等小于 int 型数据类型做运算时才会发生,比如上例的左移运算和赋值运算,如果没有运算动作,是不会发生的。

为加深理解看下下面的例子:

#include <stdio.h>
  
int main()
{
    char a = 0xfb;
    unsigned char b = 0xfb;
  
    printf("a = %c", a);
    printf("\nb = %c", b);
  
    if (a == b)
      printf("\nSame");
    else
      printf("\nNot Same");
    return 0;
}

output:

a = ?
b = ?
Not Same 

可以看到这个例子中的 a 和 b,都被初始化为字符 '?',不同是一个是 unsigned 一个是 signed。在对两个变量没做任何运算时,直接输出两个变量,输出值都一样是字符'?'。但当对两个字符做运算时(if 条件判断中的 a==b),编译器会先将 a 和 b 都转化成 int 型,因为 a 是 signed char,a转化成 int 后的值是 -5;b 是 unsigned char,b 转化成 int 后的值是 251。== 运算是在编译器将两个变量都转成 int 后才执行的,此时两个变量的值不同,所以输出 not same。

C integer promotion 介绍原文

下面把一个介绍 C integer promotion 的原文转载过来,因为是国外网站的帖子不好打开,就直接粘贴过来了,网址是 Integer Promotions in C - GeeksforGeeks  

Some data types like char short int take less number of bytes than int, these data types are automatically promoted to int or unsigned int when an operation is performed on them. This is called integer promotion. For example no arithmetic calculation happens on smaller types like charshort and enum. They are first converted to int or unsigned int, and then arithmetic is done on them. If an int can represent all values of the original type, the value is converted to an int . Otherwise, it is converted to an unsigned int.

For example see the following program.

#include <stdio.h>
int main()
{
	char a = 30, b = 40, c = 10;
	char d = (a * b) / c;
	printf ("%d ", d);
	return 0;
}

Output:

120

At first look, the expression (a*b)/c seems to cause arithmetic overflow because signed characters can have values only from -128 to 127 (in most of the C compilers), and the value of subexpression ‘(a*b)’ is 1200 which is greater than 128. But integer promotion happens here in arithmetic done on char types and we get the appropriate result without any overflow.

Consider the following program as another example.

#include <stdio.h>

int main()
{
	char a = 0xfb;
	unsigned char b = 0xfb;

	printf("a = %c", a);
	printf("\nb = %c", b);

	if (a == b)
	printf("\nSame");
	else
	printf("\nNot Same");
	return 0;
}

Output:

a = ?
b = ?
Not Same 

When we print ‘a’ and ‘b’, same character is printed, but when we compare them, we get the output as “Not Same”.
‘a’ and ‘b’ have same binary representation as char. But when comparison operation is performed on ‘a’ and ‘b’, they are first converted to int. ‘a’ is a signed char, when it is converted to int, its value becomes -5 (signed value of 0xfb). ‘b’ is unsigned char, when it is converted to int, its value becomes 251. The values -5 and 251 have different representations as int, so we get the output as “Not Same”.

We will soon be discussing integer conversion rules between signed and unsigned, int and long int, etc.

References:
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V40F_HTML/AQTLTBTE/DOCU_067.HTM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值