correct way to assemble 16bit twos complement value - Page 1
Forum section: electronics / beginners

author: V_King
author_rank: Regular Contributor
timestamp: December 08, 2015, 11:59:18 am
content: Hello,I am struggling to assemble a 16bit twos complement value from two 8 bit registers in C.I've got:Code:int8_t data0 //LSB byteint8_t data1 //MSB byteint16_t data //16bit twos complement valuedata = data1;data = data << 8;data = data | data0;but kept getting just some number which makes no sense.after some googling I found this approach:Code:int8_t data0 //LSB byteint8_t data1 //MSB byteint16_t data //16bit twos complement valuedata = data1 & 0xFF;data = data << 8;data = data | (data0 & 0xFF);is providing the numbers which look like correct readings. But I do not understand what difference does it '& 0xFF' make.Would appreciate if someone could help me to fill in gaps with bitwise operation like this.Thanks

author: DJohn
author_rank: Regular Contributor
timestamp: December 08, 2015, 12:15:25 pm
content: Code:int8_t data0 //LSB byteint8_t data1 //MSB byteint16_t data //16bit twos complement valuedata = data1 & 0xFF;data = data << 8;data = data | (data0 & 0xFF);You should only need the second & 0xff here.You've told it that data0 is a signed 8 bit number. But then you or it with a signed 16 bit number (data), so the compiler has to convert it to 16 bits first. If the top bit is set, it'll be interpreted as negative, and the entire top byte of the result will get set. That's not what you want, so you're having to mask out that top byte.If data0 and data1 were unsigned, your first code would work. And that makes sense - you're not treating them as signed numbers themselves, but just collections of bits.

author: Ian.M
author_rank: Super Contributor
timestamp: December 08, 2015, 12:20:43 pm
content: Sign extension: When C promotes a negative integer, it fills in the high byte(s) with all '1' bits to preserve the numeric value. e.g. -11 is 0xFFF5 in 16 bits or 0xF5 in 8.try:Code:data=data1*256+data0;

author: newbrain
author_rank: Super Contributor
timestamp: December 09, 2015, 10:19:57 am
content: To be pedantic, the only compliant C is the one in Ian's answer.The reason can be found in the standard (from C99 draft,6.5.7, Bitwise shift operators, emphasis mine):QuoteWhat this means in layman terms is that if your shift affects the sign bit in a signed number, the result is not defined (actually, worse: undefined behavior).Will it work? Yes, often, but it's not guaranteed to and it can change from compiler to compiler and even with revisions of the same compiler on the same architecture.In general, shift operators are more safely used with unsigned integers.Ian's answer is only relying on the internal representation of integers to be 2's complement, that is an implementation defined aspect (not undefined: the compiler vendor must provide this information) and, nowadays, an almost safe assumption. It's also definitely cleaner and shorter.

author: V_King
author_rank: Regular Contributor
timestamp: December 15, 2015, 12:00:41 pm
content: thanks for all the answers. treating raw data as uint8_t worked perfectly. I always know that msb of the MSB is always a sign bit for signed integer, so as long as I shift it to correct place, the signed integer then should be interpreted correctly.