views:

1867

answers:

4

Hi..

Can't exactly find a way on how to do the following in C/C++.

Input : hexdecimal values, for example: ffffffffff...

I've tried the following code in order to read the input :

uint16_t twoBytes;
scanf("%x",&twoBytes);

Thats works fine and all, but how do I split the 2bytes in 1bytes uint8_t values (or maybe even read the first byte only). Would like to read the first byte from the input, and store it in a byte matrix in a position of choosing.

uint8_t matrix[50][50]

Since I'm not very skilled in formating / reading from input in C/C++ (and have only used scanf so far) any other ideas on how to do this easily (and fast if it goes) is greatly appreciated .

Edit: Found even a better method by using the fread function as it lets one specify how many bytes it should read from the stream (stdin in this case) and save to a variable/array.

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

Parameters

ptr - Pointer to a block of memory with a minimum size of (size*count) bytes.

size - Size in bytes of each element to be read.

count - Number of elements, each one with a size of size bytes.

stream - Pointer to a FILE object that specifies an input stream.

cplusplus ref

+2  A: 

%x reads an unsigned int, not a uint16_t (thought they may be the same on your particular platform).

To read only one byte, try this:

uint32_t byteTmp;
scanf("%2x", &byteTmp);
uint8_t byte = byteTmp;

This reads an unsigned int, but stops after reading two characters (two hex characters equals eight bits, or one byte).

strager
"%2x" still expects an unsigned int, so your code has undefined behavior. This will probably work on a little-endian machine, but it won't work on a big-endian machine. You want to use "%hhx" instead.
Adam Rosenfield
@Rosenfield, Ah, I overlooked that when writing my answer (but considered it when thinking about it). Also, the hh modifier is non-standard (GCC-specific).
strager
I still don't think that endianness is an issue. When doing all of these operations, the compiler is smart enough to treat byteTmp as a single number, not as 4 bytes, so when you read into it, you get a 1 byte number put into a 4 byte value, it goes in fine. When you cast, it takes the correct bits.
Brian Postow
@Postow, Rosenfield was referring to my original code (which scanf'd directly to the uint8_t, which is illegal).
strager
A: 

You should be able to split the variable like this:

uint8_t LowerByte=twoBytes & 256;
uint8_t HigherByte=twoBytes >> 8;
Adrian Grigore
You may have endian issues there.
strager
Not likely, because numbers are numbers are numbers, always big end to the left. endian issues only occure when you have a bitstream that you have to interpret...
Brian Postow
Actually, this is interesting: If the text's endianness and the system's endianness differed, twoBytes would be swapped when read from the stream, but then lowerByte and higherByte would be correct because the bytes are swapped AGAIN. I would prefer to play it safe, though, and not worry about that.
strager
Exactly. OR, you can think of it as right shift gives you not necessarily the 8 bits in the 1st byte, but the LEFTMOST 8 bits, when viewed as a normal 16 bit number (not a 2 byte number)
Brian Postow
A: 

A couple of thoughts:

1) read it as characters and convert it manually - painful

2) If you know that there are a multiple of 4 hexits, you can just read in twobytes and then convert to one-byte values with high = twobytes << 8; low = twobyets & FF;

3) %2x

Brian Postow
you probably meant high = twobytes >> 8
Adrian Grigore
I'm dyslexic. I have a permit...
Brian Postow
Or you have endian issues ;-)
Adrian Grigore
+1  A: 

Thanks for the replies and comments.

The easiest solution seems to be by using scanf and hhx format.

Reading it as twobytes and then masking and shifting seems like an alternative but thats extra works there (even if it's probably not noticable).

Thanks once again !

Milan