来自" int" to" unsigned short"在应用按位运算符"〜"

时间:2014-10-06 09:26:40

标签: c casting

我使用的静态分析工具会对此代码发出警告:

uint16 var1 = 1U;
uint16 var2 = ~var1;

我查看了MISRA C 2004规则,我找到10.5规则:

  

如果按位运算符〜和<<应用于基础类型 unsigned char unsigned short 的操作数,结果应立即转换为操作数的基础类型。

好吧,这不是问题,应用隐式强制转换(我认为“强制转换”意味着隐式或显式强制转换)。但10.1规则说:

  

整数类型表达式的值不得隐式转换为表达式复杂的不同基础类型。

先前的复杂操作示例是:~u16a

我将代码更改为:

uint16 var1 = 1U;
uint16 var2 = (uint16) ~var1;

我获得了另一个警告:我认为将int负值转换为unsigned int值并不安全。我检查了C99标准(ISO C99)§6.3.1.3但我不明白是否明确指定 int unsigned short 的转换。

EmbeddedGurus article中,我读到了:

c = (unsigned int) a; /* Since a is positive, this cast is safe */

我的问题:

  1. 是否已从 signed int 明确转换为 unsigned short 未指定的行为?
  2. 如果是,如何以安全的方式使用带有unsigned short的补码运算符?

2 个答案:

答案 0 :(得分:13)

在计算值之前,算术运算符和按位运算符的操作数始终经历标准促销。短于int的任何内容都会提升为intunsigned int,具体取决于平台(即取决于int是否可以代表'正在晋升)。

在您的平台上,uint16_t标准提升为int,因为您的int可以代表uint16_t的所有值。然后将按位否定应用于int值,这是问题的原因。

要获得独立于平台的确定性结果,请自行将值转换为unsigned int

 uint16_t var2 = (uint16_t) ~((unsigned int) var1);

请注意,这始终是正确的,因为unsigned int需要能够代表uint16_t的所有值。

答案 1 :(得分:4)

  
      
  1. 是否有从signed int到unsigned short unspecified行为的显式转换?
  2.   

从签名到无符号值的转换已明确指定,它通过模运算发生,由C99草案标准中的6.3.1.3 有符号和无符号整数部分涵盖:

  

否则,如果新类型是无符号的,则通过重复添加或转换该值   减去一个可以在新类型中表示的最大值   直到该值在新类型的范围内。 49)

因此,对于您的情况,负数将通过重复添加来转换:

UMAX + 1 

到否定结果,直到它是您要转换为的无符号类型的范围。

例如,将-1转换为无符号类型始终会产生最大无符号值,因为-1 + UMAX + 1始终为UMAX

  
      
  1. 如果是,如何以安全的方式使用带有unsigned short的补码运算符?
  2.   

当您应用~运算符时会发生的情况是,由于整数提升应用于~的操作数,该值将被提升为 int 6.5.3.3 一元算术运算符中包含哪些内容(强调我的):

  

整数促销在操作数上执行,结果   有推广类型。如果提升的类型是无符号类型,则   表达式~E等于其中可表示的最大值   类型减去E

鉴于引用段落中的最后一句可能首先转换为 unsigned int 可能会产生更直观的结果:

uint16 var2 = ~((unsigned int)var1);

并且由于您需要应用显式强制转换,因此您最终会得到:

uint16 var2 = (uint16) ~((unsigned int)var1);