我有一个16位无符号变量。我需要将其分成8位块。
是否已完成以下操作:
chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);
或者我应该使用口罩:
chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);
我知道这两种方法都行得通,如果有的话,我只是在寻找最佳方法。也许没有,只是使用强制转换来减少计算是最好的方法?你们怎么看?
答案 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有符号和无符号整数
- 将整数类型的值转换为_ Bool以外的其他整数类型时(如果该值) 可以用新类型表示,但不变。
- 否则,如果新类型是无符号的,则通过反复加或减来转换值 比新类型可以表示的最大值多一个,直到该值位于 60)
- 否则,将对新类型进行签名,并且无法在其中表示值;要么结果是 实施定义或实施定义的信号被引发。
但是,很可能两者都会导致相同的编译器输出。我通常会添加掩码,因为它可以清楚地说明应该执行的代码,并且不需要强制转换。
答案 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变量选择了正确的名称)。