Reading 16-bit raw data

J

junk5

Hi

I need to read raw 16 bit data from a file, where the first byte is the
most significant byte of the first data value and the second byte is
the least significant byte of the first data value (the next pair or
bytes and the next etc. specify the second and third values).

For example, if I had a file containing

0xff22
0xfe23
0x11ff
0x1000

then the two values I should read back would be:

0x01002023
and
0x00120F00

I wrote the following code snippet which I thought would read the data:

// The input and output variables are ifstream and ofstream objects
respectively.
char currentByte[1]; // A buffer for reading the file.
unsigned int thisValue;
bool oddByte = true; // The first byte is odd-numbered, the second is
even-numbered, etc.
while(input->good()) // While we can extract data from the input
file.
{
// Get the next byte, and write the next value if the byte read
is an even byte.
input->read(currentByte, 1); // Probably inefficient, but I'll
speed things up later.
if(oddByte)
{
thisValue = (unsigned int)(*currentByte); // Most significant byte.
*output << "No mult.: thisValue is: " << thisValue << std::endl; //
Debug noise.

thisPixel *= 256; // Equiv. to leftshift by 8 places.
*output << "Current thisValue is: " << thisVaule << std::endl; //
Debugg noise.
}
else
{
thisValue += (unsigned int)(*currentByte); // Least significant
byte.
*output << "Current thisValue is: " << thisValue << std::endl; //
Debug noise.
*output << thisValue << " "; // Write out the computed value
in decimal.
}

// Invert oddByte.
oddByte = !oddByte;
}

If the above is a bit impenetrable, here's my thinking: each value in
the file is represented by two bytes, an odd byte (the MSB) and an even
byte (the LSB). oddByte is inverted after every read. If we just read a
MSB, then we need to left-shift the bits read by 8 binary places (I do
a multiply by 256 above, but it's the same thing). If we just read a
LSB, then we need to add this onto the result of doing the left-shift
by 8. After adding the LSB I write out the value to an output stream
(the other writes are just for debugging purposes).

I compile the above using gcc -Wall and it compiles cleanly. The code
runs OK, but I don't get out what I expect; instead I get values like:

4294967229
4294950144
4294950263
4294967241
4294953216
4294953122

which are far too big to have come from 16-bit values. (They look like
pointer addresses to me.)

It's been a long while since I've needed to do any bit-twiddling (or
used C++ in anger). Which bit of basic C/C++ have I forgotten?

Thanks,

C
 
V

Victor Bazarov

[..]
I compile the above using gcc -Wall and it compiles cleanly. The code
runs OK, but I don't get out what I expect; instead I get values like:

4294967229
4294950144
4294950263
4294967241
4294953216
4294953122

Display them in hex.
which are far too big to have come from 16-bit values. (They look like
pointer addresses to me.)

They are just large numbers (0xffff....).
It's been a long while since I've needed to do any bit-twiddling (or
used C++ in anger). Which bit of basic C/C++ have I forgotten?


Perhaps you need to have your "currentbyte" as _unsigned_char_...

V
 
L

lonngren

thisValue = (unsigned int)(*currentByte); // Most significant byte.
*output << "No mult.: thisValue is: " << thisValue << std::endl; //
Debug noise.

It's the conversion - try instead:

thisValue = (unsigned int)(*currentByte & 0xff)
, and it' will work.

/Patrick
 
B

Bob Hairgrove

It's the conversion - try instead:

thisValue = (unsigned int)(*currentByte & 0xff)
, and it' will work.

Don't you mean:

thisValue = ((unsigned int)(*currentByte)) & 0xff;

??
 
J

junk5

Hi all, and thanks for your responses.

A few minutes after posting I tried using the "int get()" function
instead of the "get(char*)" version, and things seem to work fine.

C
 
K

Kaz Kylheku

Bob said:
Don't you mean:

thisValue = ((unsigned int)(*currentByte)) & 0xff;

This is not necessary if currentByte were of type pointer to unsigned
char, rather than plain char! Use unsigned char for binary data.

An unsigned char will promote to signed int, or to unsigned int,
depending on whichever will hold all values of its type, including
sign.

On most platforms, unsigned char will promote to int, because it's
narrower, and so int can hold all unsigned char values.

The only remaining issue then is that the & 0xFF may be done against a
signed int zero value that doesn't have an all-bits-zero
representation. Under sign-magnitude, you are okay, because a negative
zero still has all-zero bits in the mantissa, but under one's
complement, zero can be represented by a bit pattern of all 1's.
Masking out the least significant 8 bits of that produces 255.

But even on hardware that uses one's complement for signed integers, I
wouldn't expect an unsigned char zero to promote to the negative flavor
of zero! That zero would have to be the result of some arithmetic
computation involving negative values.

So basically, you are worried to portability to one's complement
machines on which conversions are pathologically behaved.

If hardware like that were designed to day, it wouldn't see the light
of day. The reams of nonportable code that would not run on it would
seal its fate in the marketplace. :)
 
O

Old Wolf

I need to read raw 16 bit data from a file, where the first byte is the
most significant byte of the first data value and the second byte is
the least significant byte of the first data value (the next pair or
bytes and the next etc. specify the second and third values).

For example, if I had a file containing

0xff22

Do you mean the file contains 0xFF followed by 0x22 ?
0xfe23
0x11ff
0x1000

then the two values I should read back would be:

0x01002023
and
0x00120F00

Does anyone else follow this? I haven't had my coffee today
 
L

lonngren

Old said:
Do you mean the file contains 0xFF followed by 0x22 ?


Does anyone else follow this? I haven't had my coffee today

You're right - it should of course be 0xff followed by 0x22. In his
example he used 16bit numbers, shifted the first one 8 bits and added
the next one.
(0xff22 << 8) + 0xfe23 = 0x1002023
 
J

junk5

Do you mean the file contains 0xFF followed by 0x22 ?
Does anyone else follow this? I haven't had my coffee today

Obviously neither had I! Sorry all---I was 'forgetting' that one hex
digit was four bits, rather than two, but I hope the example served its
purpose.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top