应用按位运算符“〜”后,从“int”转换为“unsigned short”

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

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

我检查了MISRA C 2004规则,我发现10.5规则:

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

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

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

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

我将我的代码更改为:

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

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

在EmbeddedGurus文章中我读到:

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

我的问题:

  1. 是否有从signed intunsigned short unspecified行为的显式转换?
  2. 如果是,如何以安全的方式使用带有unsigned short的补码运算符?

在计算值之前,算术运算符和按位运算符的操作数始终经历标准促销 。 任何比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. 是否有从signed int到unsigned short unspecified行为的显式转换?

从有符号值到无符号值的转换已经明确规定,它通过模运算发生,见6.3.1.3 C99标准草案中的有符号和无符号整数

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

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

 UMAX + 1 

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

例如, -1转换为无符号类型总是导致最大无符号值,因为-1 + UMAX + 1始终为UMAX

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

应用~运算符时会发生的情况是,由于将整数提升应用于〜的操作数,该值将被提升为int6.5.3.3 一元算术运算符强调我的 )中包含了这一点:

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

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

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

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

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