Tuesday, March 1, 2011

C/C++ read a byte from an hexinput from stdin

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

From stackoverflow
  • %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).

    Adam Rosenfield : "%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.
    strager : @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).
    Brian Postow : 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.
    strager : @Postow, Rosenfield was referring to my original code (which scanf'd directly to the uint8_t, which is illegal).
  • You should be able to split the variable like this:

    uint8_t LowerByte=twoBytes & 256;
    uint8_t HigherByte=twoBytes >> 8;
    
    strager : You may have endian issues there.
    Brian Postow : 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...
    strager : 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.
    Brian Postow : 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)
  • 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

    Adrian Grigore : you probably meant high = twobytes >> 8
    Brian Postow : I'm dyslexic. I have a permit...
    Adrian Grigore : Or you have endian issues ;-)
  • 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 !

0 comments:

Post a Comment