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

no_*_*ame 12 c casting

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

uint16 var1 = 1U;
uint16 var2 = ~var1;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

我将我的代码更改为:

uint16 var1 = 1U;
uint16 var2 = (uint16) ~var1;
Run Code Online (Sandbox Code Playgroud)

我得到另一个警告:我认为将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 */
Run Code Online (Sandbox Code Playgroud)

我的问题:

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

Ker*_* SB 14

在计算值之前,算术运算符和按位运算符的操作数始终经历标准促销.任何比a更短的东西都会int被提升为int或者unsigned int,取决于平台(即取决于是否int可以代表所提升类型的所有值).

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

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

 uint16_t var2 = (uint16_t) ~((unsigned int) var1);
Run Code Online (Sandbox Code Playgroud)

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


Sha*_*our 5

  1. 是否已从有符号的int显式转换为无符号的短未指定行为?

C99草案标准的有6.3.1.3 符号和无符号整数部分介绍了通过模算术进行从有符号到无符号值的转换的详细说明:

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

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

UMAX + 1 
Run Code Online (Sandbox Code Playgroud)

直到结果为您要转换为无符号类型的范围。

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

  1. 如果是,如何以安全的方式使用无符号短补码?

应用~运算符时会发生的情况是,由于将整数提升应用到的操作数,因此将值提升为int~6.5.3.3 一元算术运算符小节中对此进行了介绍(强调我的话):

整数的促销活动的操作数加以执行,并且结果具有提升的类型。如果提升的类型是一个无符号类型,表达式〜E是相当于该类型减去E中的最大值表示的

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

uint16 var2 = ~((unsigned int)var1);
Run Code Online (Sandbox Code Playgroud)

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

uint16 var2 = (uint16) ~((unsigned int)var1);
Run Code Online (Sandbox Code Playgroud)