C 是否应该使用强制转换来截断长变量?

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); 我知道这两种方法都有效,我只是在寻找最好的方法,如果有的话。

我有一个16位无符号变量。我需要把它分成8位的块

做到以下几点是否足够:

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有符号和无符号整数
  • 当整数类型的值转换为除Bool以外的其他整数类型时,如果 可以用新类型表示,它是不变的
  • 否则,如果新类型是无符号的,则通过重复加减来转换该值 比新类型中可以表示的最大值多出一个值,直到该值位于 新类型的范围。60)
  • 否则,新类型已签名,且无法在其中表示值;要么结果是 已定义实现或发出了已定义实现的信号
  • 但是,很可能两者都会产生相同的编译器输出。我通常添加掩码,因为它明确了代码应该做什么,并且使强制转换变得不必要

    是否应该使用强制转换来截断长变量

    如果
    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&mask0xFF
    vs
    one'u byte\u bit\u mask\u 0xFF
    vs
    mask
    ,我选择第二个选项作为最不坏的选项。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 );