使用类型转换删除gcc编译器警告

我正在使用gcc 4.9进行嵌入式ARM编程。 我一直在使用-Wconversion开关,因为它在我公司的默认开发工具配置中。 我正在使用stdint.h 类型 (uint8_t,uint32_t等)。

每次执行复合赋值或简单添加时,编译器都会创建警告。 例如:

 uint8_t u8 = 0; uint16_t u16; // These cause warnings: u8 += 2; u8 = u16 >> 8; 

修复此问题的“常用方法”是使用强制转换,如此处和此处所述 :

 u8 = (uint8_t)(u8 + 2); u8 = (uint8_t)(u16 >> 8); 

除了这个丑陋之外,我还在不断地遇到令人信服的证据,certificate施法通常是不好的做法。

我的问题:

  1. 为什么以这种方式使用类型转换是不好的?
  2. 通过简单地省略-Wconversion并让编译器为我做隐式转换,我会失去什么吗?

编译器向您显示潜在的问题点,您应该考虑更改,但不能通过强制转换。 你所拥有的代码中的问题是,在C中,算术永远不会在比int更窄的类型上完成:编译器总是为它们执行对int的隐式转换。

因此,有效的代码是将窄的无符号类型转换为int ,执行操作然后将它们转换回无符号类型。

通常使用窄类型进行算术并不是一个好主意。 只有在存储大小有问题时才使用它们(通常是较大的结构,如数组)。 对于本地的,或多或少的临时变量,这些狭义类型毫无意义。

这是一个品味问题。 当您将算术类型的值分配给不同算术类型的对象时,C从不需要强制转换。 有些人使用演员表来记录隐藏的转换,并且他们故意这样做。

我个人不喜欢把更多无用的东西,我认为读者知道C的基本知识,所以我倾向于避免演员表(我不使用-Wconversion ,它不是-Wall甚至-Wextra的一部分)。 请注意,在赋值中,如果右侧的文字不能适合左侧对象,则gcc通常会发出警告(不使用-Wall-Wextra ),即使赋值不是UB。

强制转换的问题在于它们告诉编译器“闭嘴,我知道我在做什么”,即使你没有。 如果某人决定该变量必须能够处理大于255的值并将类型更改为uint16_t,则u8 + = 2将起作用,但u8 =(uint8_t)(u8 + 2)将被破坏。 例如,假设变量没有命名为u8而是命名为“numberOfParagraphs”,那可能是一个很难找到的bug。

最好先使用更大的类型。 除非你真的,真的想存储(u8 + 2)和0xff,在这种情况下你可以这样写它并将它存储到一个更大的变量而没有问题。

(就个人而言,我希望对语言进行扩展

 (uint8_t)u8 += 2; 

使用将左值转换为自己的类型的语义没有效果,并且在删除警告时它仍然是左值,但是将左值转换为其他类型将是一个错误。 这样可以安全地关闭编译器警告)