views:

257

answers:

5

I can do this:

int main(int argc, char** argv) {
  unsigned char cTest = 0xff;
  return 0;
}

But what's the right way to get a hexadecimal number into the program via the command line?

unsigned char cTest = argv[1];

doesn't do the trick. That produces a initialization makes integer from pointer without a cast warning.

+7  A: 

You could use strtoul which would walk through the characters in the string and convert them, taking into account the radix (16 in this context) that you pass in:-

char *terminatedAt;
if (argc != 2)
    return 1;

unsigned long value = strtoul( argv[1], &terminatedAt, 16);

if (*terminatedAt != '\0')
    return 2;

if (value > UCHAR_MAX)
    return 3;

unsigned char byte = (unsigned char)value;
printf( "value entered was: %d", byte);

As covered in the other examples, there are shorter ways, but none of them allow you to cleanly error check the processing (what happens if someone passes FFF and you've only got an unsiged char to put it into?

e.g. with sscanf:

int val;
sscanf(argv[1], &val)
printf("%d\n", val); 
Ruben Bartelink
`UCHAR_MAX` may be greater than `LONG_MAX`, so you should use `strtoul()`, and `value > 255` should be `value > UCHAR_MAX`. Finally, `static_cast` is C++; here you don't need a cast because of implicit conversion rules.
Alok
Ta, I had a `cout` in it in the intial version :P I considered using u initially but thought it would complicate matters too much given that the questioner is mainly looking to understand a concept that isnt immediately obvious to them.
Ruben Bartelink
@Ruben: I agree that sometimes one has to make things not-entirely-pedantically-correct for beginners, but in this case I think the pedantry isn't too hard, even for a beginner. It will prevent many people from assuming that `UCHAR_MAX == 255` or `LONG_MAX > UCHAR_MAX`, etc. Thanks for the edit and a good answer!
Alok
@Alok: Always happy to be pedantic, thanks! I think the cast is good here as it explains what's happening to a reader and will avoid warnings about the shortening conversion shoudl they be switched on. I'll leave out mbs concerns (and wchar_t concerns as the question ruled them out). Over and out!
Ruben Bartelink
+2  A: 
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  printf("%ld\n", strtol(argv[1], NULL, 16));

  return 0;
}

Example usage:

$ ./hex ff
255
Greg Bacon
A: 

atoi, atol, strtoi, strtol

all in stdlib.h

Pod
All pointed out 3 mins before (the see also of the linked man page) but not helping the questioner understand why its necessary or giving a sample. When a post isnt adding, it's good to delete it to keep it DRY
Ruben Bartelink
+2  A: 
unsigned char cTest = argv[1];

is wrong, because argv[1] is of type char *. If argv[1] contains something like "0xff" and you want to assign the integer value corresponding to that to an unsigned char, the easiest way would be probably to use strtoul() to first convert it to an unsigned long, and then check to see if the converted value is less than or equal to UCHAR_MAX. If yes, you can just assign to cTest.

strtoul()'s third parameter is a base, which can be 0 to denote C-style number parsing (octal and hexadecimal literals are allowed). If you only want to allow base 16, pass that as the third argument to strtoul(). If you want to allow any base (so you can parse 0xff, 0377, 255, etc.), use 0.

UCHAR_MAX is defined in <limits.h>.

Alok
+1 good explanation, taking in the reasoning behind most of the points I'm trying to show in the code
Ruben Bartelink
+1  A: 

The traditional way to do this kind of thing in C is with scanf(). It's exactly the inverse of printf(), reading the given format out of the file (or terminal) and into the variables you list, rather than writing them into it.

In your case, you'd use sscanf as you've already got it in a string rather than a stream.

T.E.D.