8

I have a program that requires the user to enter an integer as a command line argument, in the form of ./program 100.

Obviously this will read the value in as a string, so I need to parse it to an integer. I have to ensure that the input value won't overflow an integer variable. I have read about strtol(), but it works with long variables and I have to stick with a regular int.

Is there anything similar that can be used for an int?

dbush
  • 205,898
  • 23
  • 218
  • 273
Jake
  • 229
  • 3
  • 12

2 Answers2

7

You can use strtol for this. You'll first need to check if this function fails to convert the value. If it convert successfully, then check if the value is in the range of INT_MIN to INT_MAX:

errno = 0;
long x = strtol(argv[1], NULL, 10);
if (errno) {
    perror("conversion failed");
} else if (x < INT_MIN) {
    printf("value too small\n");
} else if (x > INT_MAX) {
    printf("value too big\n");
} else {
    printf("value = %ld\n", x);
}

Note that this will work whether long is the same size as int or larger.

If sizeof(long) > sizeof(int), the INT_MIN and INT_MAX checks will catch the cases where the value fits in a long but not an int. If sizeof(long) == sizeof(int), an out of range value will result in errno being set to non-zero to catch the error, and the INT_MIN and INT_MAX cases will never be true.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    Strictly speaking, it's the ranges of `int` and `long` that are relevant here, not their sizes. In the presence of padding bits, it's possible for `int` and `long` to have the same size, but for `long` to have a wider range. (Few if any implementations actually use padding bits, though.) – Keith Thompson Apr 01 '19 at 20:49
  • 1
    `if (errno) {` is not a sufficient test to detect "conversion failed" as `errno` can still be 0. – chux - Reinstate Monica Apr 01 '19 at 23:46
  • @KeithThompson C++20 makes padding bits illegal and two's complement mandatory representation for signed integers. This decision was made after they realized two's complement is de facto used exclusively by any platform deemed relevant. So, I wouldn't worry to much about that. – bolov Apr 02 '19 at 11:26
  • @bolov: The question is about C, not C++. (A new C standard *might* make a similar change). And the standard describes this in terms of ranges, not sizes. It's just as easy to be precise. – Keith Thompson Apr 02 '19 at 19:33
  • @KeithThompson my bad, didn't see the C tag – bolov Apr 02 '19 at 19:56
  • 1
    @chux: Right. `strtol()` will give you all the information you want, but coaxing that information out of the results can be tricky. It quietly ignores leading white space and trailing garbage. and it returns `0` without setting `errno` if no conversion was possible (for example for `"xyz"`). You have to use the `endptr` argument to find out what it actually did. – Keith Thompson Apr 02 '19 at 23:54
1

How should I verify that an integer value passed in from argv won't overflow?

Use strtol() and check the end pointer. Then check errno and maybe a range test

if (argc > 1) {
  char *endptr;
  errno = 0;
  long num = strtol(argv[1], &endptr, 10);

  if (argv[1] == endptr) {
    puts("No conversion");
  } else if (errno == ERANGE) {
    puts("Value outside long range");
  #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
  } else if (num < INT_MAX || num > INT_MAX) {
    errno = ERANGE;
    puts("Value outside int range");
  #endif
  } else {
    // If code wants to look for trailing junk
    if (*endptr) {
      puts("Non-numeric text");
    } else {
      printf("Success %d\n", (int) num);
    } 
  } 

Based on Why is there no strtoi in stdlib.h?

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256