我有以下C代码:
typedef unsigned char uint8_t;
void main(void) {
uint8_t a = 1, b = 2, res;
res = a + b;
}
当我使用gcc -Wconversion
编译此代码时,我收到以下警告:
test.c: In function 'main':
test.c:5:10: warning: conversion to 'uint8_t' from 'int' may alter its value [-Wconversion]
有人可以解释为什么会出现此警告吗?所有三个变量都是uint8_t
类型,因此我并不真正了解int
的来源。
答案 0 :(得分:9)
我真的不明白
int
的来源。
int
来自C语言标准。算术运算符的所有操作数在执行操作之前都会被提升。在这种情况下,uint8_t
会提升为int
,因此您需要使用强制转换来避免警告:
res = (uint8_t)(a + b);
以下是标准定义整数促销的方式:
6.3.1.1如果
int
可以表示原始类型的所有值,则该值将转换为int
;否则,它将转换为unsigned int
。这些被称为整数 促销。
由于int
可以包含uint8_t
的所有可能值,a
和b
会被提升为int
以进行添加操作。
答案 1 :(得分:4)
只是要添加有关整数促销的现有答案,也可能值得解释-Wconversion
警告你的内容。
由于a
和b
都是uint8_t
,因此a + b
的结果可能不适合另一个uint8_t
。通过将结果分配回uint8_t
,可以强制编译器执行可能更改值的转换。因此,res
变量实际上可能并不代表a + b
的实际值。
例如,如果a
和b
都是0xff
,那么:
a + b
为0x1fe
,类型为int
(uint8_t)(a + b)
是0xfe
答案 2 :(得分:0)
您应该阅读有关C int promotion rules的更多信息。这是规则,因此编译器必须遵守。没有它,一些“琐碎”的代码将无法工作(就像你预期的那样)。例如
char d[4] = {0xFF, 0xFE, 0x80, 40};
int i = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
int j = d[2] - d[0]*d[1];
在一些8位微控制器的编译器中,有一个选项可以禁用C标准构造来加速数学运算,因为始终将char提升为int来进行数学运算可能会导致不必要的操作并减慢进程。它还消耗更多内存,这在这种嵌入式系统中是有价值的。当然它会使一些代码不可移植或根本不工作,但这是权衡。
现代微处理器是16位或更多,因此使用char不会使您免于任何操作,但由于每次操作之前/之后的符号调整,也可能增加代码大小和速度。除了加载/存储和符号扩展之外,大多数RISC体系结构甚至没有操作与操作数不同的操作数的指令。所以建议对所有临时使用本机int大小。小于本机寄存器大小的类型只应用于可能增加高速缓存未命中的非常大的数组,保存或读取某些其他类型的内存中的数据或与其他系统/库兼容的情况