3

I've been reading sources for a while but they're always talking about overflows when doing operations but how do I really check for potential int overflow the moment it was entered by the user before it can be assigned to the int identifier?

I want to check the input the moment it was entered so when found that such value already exceeded the range of value for int type data, I can put a stop to it before it even proceeds to the next part of the code.

4
  • Do bounds checking on the result. If it's not acceptable, error out. Commented Feb 19, 2019 at 16:49
  • 2
    @tadman which is easier said, than done. Commented Feb 19, 2019 at 16:50
  • Overflow bugs occur when you fail to test the result and just assume it's fine. If you need to, clamp the result to acceptable bounds. Commented Feb 19, 2019 at 16:50
  • Possible duplicate of Validate max integer in scanf Commented Feb 19, 2019 at 16:52

2 Answers 2

6

You can read a string then use strtol then check the endptr and errno, when all is ok you can assign your int var

Verbose use of strtol

#include <stdlib.h>
#include <ctype.h>
#include <errno.h>

int main()
{
  char s[32]; /* 31 characters is surely large enough for an int */

  if (scanf("%31s", s) != 1)
    puts("nok");
  else {
    errno = 0;

    char * endptr;
    long int l = strtol(s, &endptr, 10);

    if (endptr == s)
      puts("no digit");
    else if ((*endptr != 0) && !isspace(*endptr))
      puts("invalid number");
    else if (errno != 0)
      puts("overflow on long");
    else if (((int) l) != l) /* in case long and int do not have the same size */
      puts("overflow on int");
    else
      puts("you enter a valid int");
  }

  return 0;
}

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra s.c
pi@raspberrypi:/tmp $ ./a.out
a 
no digit
pi@raspberrypi:/tmp $ ./a.out
12z
invalid number
pi@raspberrypi:/tmp $ ./a.out
123
you enter a valid int
pi@raspberrypi:/tmp $ ./a.out
12345678901
overflow on long

So to exactly answer to the question :

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>

int readInt(int * v)
{
  char s[32]; /* 31 characters is surely large enough for an int */

  if (scanf("%31s", s) != 1)
    return 0;
  else {
    errno = 0;

    char * endptr;
    long int l = strtol(s, &endptr, 10);

    if ((endptr == s) ||       /* no digit */
        ((*endptr != 0) && !isspace(*endptr)) || /* e.g. 12a */
        (errno != 0) ||        /* overflow on long */
        (((int) l) != l))      /* overflow on int */
      return 0;

    *v = (int) l;
    return 1;
  }
}


int main()
{
  int v = 123;

  if (readInt(&v))
    printf("new valid in value : %d\n", v);
  else
    printf("unvalid input, still %d\n", v);

  return 0;
}

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra s.c
pi@raspberrypi:/tmp $ ./a.out
12
new valid in value : 12
pi@raspberrypi:/tmp $ ./a.out
9878787878787878
unvalid input, still 123
pi@raspberrypi:/tmp $ 
Sign up to request clarification or add additional context in comments.

11 Comments

A comment sample worth a thousand words :)
@SergeyA what do you mean ? an example of code is missing ?
Yes, this is exactly what I mean
@SergeyA so we agree, I will ^^
You need to set errno to zero before calling strtol() otherwise there's no guarantee it will be zero should strtol() succeed.
|
1

If you must read directly into an int, you can't really check for overflow before assigning.

There are ways around that if reading directly into int is not a requirement. For example, you can read into a character buffer/string and then check if the input was numeric and if it will fit into an int. If so, you then convert character buffer to an integer using standard library functions and assign to your int.

1 Comment

A comment sample worth a thousand words :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.