是否应使用强制转换来截断long变量?

时间:2019-02-25 12:41:34

标签: 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);

我知道这两种方法都行得通,如果有的话,我只是在寻找最佳方法。也许没有,只是使用强制转换来减少计算是最好的方法?你们怎么看?

4 个答案:

答案 0 :(得分:7)

目前尚不清楚variable是什么类型。如果没有指定,我们只能推测。

但是,通常,应避免对有符号整数类型进行位移位,因为这会导致各种形式的定义不明确的行为。反过来,这也意味着您也必须注意小整数类型,因为它们会被提升为带符号的int。参见Implicit type promotion rules

如果(uint8)((variable >> 8) & 0xFFu);是未签名的,则variable的特定情况是安全的。否则,这是不安全的,因为右移负值会导致实现定义的行为(算术或逻辑移位)。

variable << 8将在16位系统上调用未定义的行为,以防variable是小整数类型或int16_t

因此,无论向左/向右移动,最安全,最便携的方式是:

chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);

尽管您可能想要过分明确以使所有编译器警告均消失:

chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );

答案 1 :(得分:4)

由于uint8是未签名的,因此您没有进行屏蔽:

  

6.3.1.3有符号和无符号整数

     
      
  1. 将整数类型的值转换为_ Bool以外的其他整数类型时(如果该值)   可以用新类型表示,但不变。
  2.   
  3. 否则,如果新类型是无符号的,则通过反复加或减来转换值   比新类型可以表示的最大值多一个,直到该值位于    60)
  4.   
  5. 否则,将对新类型进行签名,并且无法在其中表示值;要么结果是   实施定义或实施定义的信号被引发。
  6.   

但是,很可能两者都会导致相同的编译器输出。我通常会添加掩码,因为它可以清楚地说明应该执行的代码,并且不需要强制转换。

答案 2 :(得分:3)

  

是否应该使用强制类型转换来截断long变量?

如果// definition template<typename T, T N> struct print_constexpr{ [[deprecated]] print_constexpr(){ } }; // usage print_constexpr<unsigned int, Factorial<5>::value> x; // output {path to file}: warning: ‘print_constexpr<T, N>::print_constexpr() [with T = unsigned int; T N = 120]’ is deprecated [-Wdeprecated-declarations] print_constexpr<unsigned int, Factorial<5>::value> x; 是8位对象(比chunk_lsb窄),请使用强制转换或mask (不能同时使用)。在消除有关范围缩小的学问警告时很有用。我更喜欢面具-除非编译器挑剔。

variable

否则,请使用口罩。

uint8_t chunk_lsb = (uint8_t) variable;
// or 
uint8_t chunk_lsb = variable & 0xFFu;

答案 3 :(得分:-1)

  

也许没有,只是使用强制转换来减少计算是最好的方法?

一般来说,asm代码是相同的,因此从速度上来说,使用哪一个都无所谓:

  

你们怎么看?

IMO,就可读性而言,第一个更为清晰,但是我无法找出支持我偏好的编码标准或准则。无论如何,如果您的偏好是第二个,我将使用const变量,以删除幻数并更清楚地表明其目的是掩盖(假设您为const变量选择了正确的名称)。