将两个uint8_t组合成uint16_t

32

我有以下数据

uint8_t d1=0x01; 
uint8_t d2=0x02; 

我想将它们组合为uint16_t

uint16_t wd = 0x0201;

我该怎么做?

4个回答

54
你可以使用位运算符:
uint16_t wd = ((uint16_t)d2 << 8) | d1;

因为:
 (0x0002 << 8) | 0x01 = 0x0200 | 0x0001 = 0x0201

2
是的,它需要先转换d2(编辑后的帖子已经处理了这个问题)。 - Jonathan Grynspan
@LuchianGrigore:哦,是的,我忘了。谢谢。 - md5
我不认为强制类型转换会有任何改进。假设uint16_t的转换级别低于“int”,那么使用强制类型转换并不能解决问题,左操作数仍然会被隐式提升为(有符号)int。但由于这不可能产生负值,因此该代码的行为和原始代码始终是明确定义的。 - Lundin
@ChristianRau 好的,现在我明白你所担心的事情了。我只看了这个特定的例子,其中 (int)0x02 << 8 总是定义良好的。从一般的编程角度来看,你是正确的。 - Lundin
无论是否将升级为int的推广使转换变得多余,我总是更喜欢看到像这样的代码 - 它实际上是一个意图的“注释”。但是@R..给出了一个答案,任何优化编译器都会生成高效(例如移位)指令,没有等级/转换问题。 - Brett Hale
显示剩余6条评论

16

最简单的方法是:

256U*d2+d1

7
哎呀,现在我们真的有一个使用位运算的案例了,而你仍然坚持无聊的算术运算。 ;) - Christian Rau
2
"<<8"和"*256"是相同的操作,只是前者在更多情况下具有未定义的行为,因此通常不可取。除非右操作数是变量(这时你有一个很好的指数运算符),否则几乎没有理由使用"<< "或">>"运算符。 - R.. GitHub STOP HELPING ICE
3
没错,那条评论有些幽默的意味。 - Christian Rau
这个答案排名是如何工作的?为什么它总是出现在页面底部? - Brett Hale

11
这很简单。您不需要强制转换,也不需要临时变量,更不需要黑魔法。
uint8_t d1=0x01; 
uint8_t d2=0x02; 
uint16_t wd = (d2 << 8) | d1;

只要 d2 <= INT8_MAX,这总是有良好定义的行为,因为d2始终是正值且永远不会溢出。

(INT8_MAX可在stdint.h中找到。)


除非它不是0x7F(参见5.2.4.2),否则就是这样。 - autistic
@Lundin:由于uint8_t是默认存在的,因此CHAR_BIT等于8。而且在实践中,CHAR_MAX并不总是0x7f。有很多系统中,普通的char类型是无符号的。 - R.. GitHub STOP HELPING ICE
1
INT8_MAX 是 127。虽然当 d2<=127 时可以证明 d2<<8 不会溢出,但原因是 INT_MAX 至少应为 32767,但不必更大。 - R.. GitHub STOP HELPING ICE
1
Stackoverflow模型的缺点是,由于原始帖子的编辑,大部分讨论现在都变得毫无意义。提供INT_MAX == 32767时,INT8_MAX是巧合的上限值。当INT_MAX >= 32768时,INT8_MAX就没有意义了。 - autistic
1
@Lundin 危险并不一定在于移动符号位;在int类型的表达式中使用无法表示为int的值似乎更适合描述这种未定义行为。 - autistic
显示剩余5条评论

3
(uint16_t)((d2 << 8) + (d1 & 0x00ff))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接