C 是否应该使用强制转换来截断长变量?
我有一个16位无符号变量。我需要把它分成8位的块 做到以下几点是否足够:C 是否应该使用强制转换来截断长变量?,c,casting,mask,truncate,C,Casting,Mask,Truncate,我有一个16位无符号变量。我需要把它分成8位的块 做到以下几点是否足够: chunk_lsb = (uint8)variable; chunk_msb = (uint8)(variable >> 8); 或者我应该使用面具: chunk_lsb = (uint8)(variable & 0xFFu); chunk_msb = (uint8)((variable >> 8) & 0xFFu); 我知道这两种方法都有效,我只是在寻找最好的方法,如果有的话。
chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);
或者我应该使用面具:
chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);
我知道这两种方法都有效,我只是在寻找最好的方法,如果有的话。也许没有,只是使用cast来减少计算是最好的方法?你们觉得怎么样
也许没有,只是使用cast来减少计算是最好的方法
一般来说,asm代码是相同的,因此就速度而言,使用哪种代码并不重要:
- 掩蔽:
- 铸造:
在我看来,第一个更清晰,在可读性方面,但我无法找到一个支持我偏好的编码标准或指南。无论如何,如果您的偏好是第二个变量,我会使用
const
变量来删除幻数,并更清楚地说明其目的是屏蔽(假设您为const变量选择了正确的名称)。由于uint8
是无符号的,您不必进行屏蔽:
6.3.1.3有符号和无符号整数
chunk\u lsb
是一个8位对象(比变量
窄),请使用强制转换或掩码(不能同时使用两者)。有助于消除量程减小的迂腐警告。我更喜欢掩码,除非编译器很挑剔
uint8_t chunk_lsb = (uint8_t) variable;
// or
uint8_t chunk_lsb = variable & 0xFFu;
否则,请使用面具
unsigned chunk_lsb = variable & 0xFFu;
不清楚
变量是什么类型的。如果没有具体说明,我们只能猜测
但一般来说,您应该避免有符号整数类型上的位移位,因为这会导致各种形式的定义不当的行为。这反过来意味着您也必须小心处理小整数类型,因为它们会升级为有符号int
。看
(uint8)((变量>>8)&0xFFu)的具体情况如果变量
未签名,则code>是安全的。否则它是不安全的,因为右移负值会导致实现定义的行为(算术或逻辑移位)
变量我认为两者将生成相同的二进制代码。由于第一个解决方案更具可读性,我将使用这个解决方案。你只需要确定uint8是8,但在所有平台上(我想是)谢谢@jaudo,这也是我的方向。旁注:标准的stdint.h
类型,比如uint8_t
应该是首选的,而不是创建自己的。除了,C有讨厌的整数提升,所以如果你尝试做同样的事情并左移,程序可能会在未定义的行为中内爆。在这个特殊的例子中,我们逃脱了,因为这是一个正数的右移。而且,演员阵容明显故意使精度下降。许多编译器可以在精度损失时发出警告,这一点非常重要。(我想到的是那些非常确定“size\u t
和指针实际上只是无符号int
…)@Lundin:在C89下,在整数类型没有填充位或陷阱表示的实现中,为所有可能的左操作数值定义了有符号左移位行为,但在强制行为与二次乘法的幂不同的情况下,陷阱可能更为合理。我没有看到任何证据证明这一点如果C89的行为和两次乘法的威力是相等的,建议改变处理方式。@supercat不管UB和符号格式如何,意外地将数据移到符号位已经够糟糕的了。@Lundin:在两次补码表示法中,符号位只是此位的状态和左侧无限多个位“。值-3是一个无穷多的1,后跟01。可以更方便地将32位二补值视为由无穷多的0或1后跟恰好31位组成,但无穷多的1,后跟29位,然后是01,与无穷多的1后跟01相同。无论如何,如果您的偏好是第二个变量,我会使用const
变量来删除幻数,并更清楚地说明其目的是掩蔽任何认为0xFF
在位掩蔽的上下文中是“幻数”的人,必须用一个变量来掩盖这一点,因为该变量正在从事cargo cult编程。有什么可能的变量比作为位掩码的0xFF
更清晰<代码>一字节位掩码0xFF
?IMO,如果目的是掩码,单词掩码比任何(魔法)数字都清晰。IMO,如果目的是掩码,单词掩码比任何(魔法)数字都清晰哦?此掩码有多少位:unsigned int result=input&mask不,我没有DV。0xFF
vsone'u byte\u bit\u mask\u 0xFF
vsmask
,我选择第二个选项作为最不坏的选项。AFAICT(变量>>8)&0xFFu
将给出相同的结果,无论移位是算术的还是逻辑的,只要int
至少有16位宽(我相信标准保证了这一点)。@IlmariKaronen,瓦里亚的大小
chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);
chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );