0

I am boxing with a C code snippet I need to convert. One of the functions is as follows:

+(float) calcTemp:(NSData *)data {
    char scratchVal[data.length];
    [data getBytes:&scratchVal length:data.length];
    UInt16 temp;
    temp = (scratchVal[0] & 0xff) | ((scratchVal[1] << 8) & 0xff00);
    return (float)temp;
}

This line I just can't seem to grasp:

temp = (scratchVal[0] & 0xff) | ((scratchVal[1] << 8) & 0xff00);

i know its probably a novo question (but I am a noob^), if someone could explain that line to me i would greatly appreciate it. In particular the things with address references and the operator uses.

In the code snippet I don't see why they call getBytes:length method on data, since its not being used. But mainly, Im just trying to understand the line that I pointed out.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
DevilInDisguise
  • 360
  • 1
  • 4
  • 14

1 Answers1

1

The line

temp = (scratchVal[0] & 0xff) | ((scratchVal[1] << 8) & 0xff00);

is creating an unsigned 16-bit integer value from two bytes originating in scratchVal. A single & in this context is not the address operator but bitwise AND. So the lower byte of temp is set from the first byte contained in scratchVal, and the upper byte of temp is set by left-shifting the second byte contained in scratchVal. The two resulting numbers are joined together using bitwise OR |. To avoid sign extension or other unwanted bits the masks 0xff and 0xff00 are used to ensure all undesirables are zero.

Presented visually, if scratchVal contains the bits aaaaaaaa bbbbbbbb in the first two bytes then temp will end up as an unsigned integer with the bit pattern bbbbbbbbaaaaaaaa.

The second question asked why they're calling -getBytes:length:. The line

[data getBytes:&scratchVal length:data.length];

reads the bytes from data into the scratchVal temporary buffer.

In response to the question in the comment

why it is needed to left shift the bits to concatenate them

A simple assignment won't work. Assuming again that scratchVal is a char buffer containing the bits aaaaaaaa bbbbbbbb, the code

temp = scratchVal[0];

would make temp equal to the UInt16 equivalent of the bits aaaaaaaa. You can't use addition because the result will be whatever value comes from adding the two bytes together (aaaaaaaa + bbbbbbbb).

Using real numbers as an example, suppose the first two bytes of scratchVal are equal to 0x7f 0x7f.

temp = scratchVal[0] + scratchVal[1];

Turns out to be 0x7f + 0x7f = 0xfe which is not the purpose of this code.

Building the value using OR can be better understood by breaking it down into steps.

The first part of the expression is scratchVal[0] & 0xff = 0x7f & 0xff = 0x7f

The second part is (scratchVal[1] << 8) & 0xff00 = (0x7f << 8) & 0xff = 0x7f00 & 0xff = 0x7f00

The final result in this case is 0x7f | 0x7f00 = 0x7f7f.

sbooth
  • 16,646
  • 2
  • 55
  • 81
  • I thought the char type was always 1byte?; at least thats what I've read. if I made a char variable[10] would it be 10 bytes? It still seems kind of difficult for me to grasp this, and why it is needed to left shift the bits to concatenate them. I appreciate your explaining though – DevilInDisguise Jan 21 '15 at 13:38
  • A `char` is almost always one byte (see http://stackoverflow.com/questions/2215445/are-there-machines-where-sizeofchar-1). See my edit for why you need to shift the bits left. – sbooth Jan 21 '15 at 22:50
  • Thanks for your more detailed answer. I think using hexadecimal doesn't simplify the point though; since the shifting is one bitwise. Anyway, I think what I have trouble understand is when you have a byte and shift it left by 8, doesn't that mean that you will overwrite the byte "to the left" of the shifted byte. Inthis case scratchVal[1] overwriting scrathval[0]. And i don't understand how shifting by 8 (hence a full byte) will put scratchVal[1] in front of scratchVal[0]. Sorry if my question are not so wise, but I have just been trying to read up on things after this post. Thanks again – DevilInDisguise Jan 22 '15 at 20:00
  • Shifting left does overwrite the bits to left but you're doing so in a temporary so `scratchVal[0]` isn't overwritten. You're creating two temporary values and then joining them together. – sbooth Jan 22 '15 at 20:27