我使用的静态分析工具会对此代码发出警告:
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 */
我的问题:
答案 0 :(得分:13)
在计算值之前,算术运算符和按位运算符的操作数始终经历标准促销。短于int
的任何内容都会提升为int
或unsigned 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)
- 是否有从signed int到unsigned short unspecified行为的显式转换?
醇>
从签名到无符号值的转换已明确指定,它通过模运算发生,由C99草案标准中的6.3.1.3
有符号和无符号整数部分涵盖:
否则,如果新类型是无符号的,则通过重复添加或转换该值 减去一个可以在新类型中表示的最大值 直到该值在新类型的范围内。 49)
因此,对于您的情况,负数将通过重复添加来转换:
UMAX + 1
到否定结果,直到它是您要转换为的无符号类型的范围。
例如,将-1
转换为无符号类型始终会产生最大无符号值,因为-1 + UMAX + 1
始终为UMAX
。
- 如果是,如何以安全的方式使用带有unsigned short的补码运算符?
醇>
当您应用~
运算符时会发生的情况是,由于整数提升应用于~
的操作数,该值将被提升为 int 。 6.5.3.3
一元算术运算符中包含哪些内容(强调我的):
整数促销在操作数上执行,结果 有推广类型。如果提升的类型是无符号类型,则 表达式~E等于其中可表示的最大值 类型减去E 。
鉴于引用段落中的最后一句可能首先转换为 unsigned int 可能会产生更直观的结果:
uint16 var2 = ~((unsigned int)var1);
并且由于您需要应用显式强制转换,因此您最终会得到:
uint16 var2 = (uint16) ~((unsigned int)var1);