Hogyan olvassunk be overflow nélkül?

Fórumok

Üdv!
Lassan két órás keresgélés töprengés után, szeretném valakinek a segítségét kérni a következő problémámval...(gondolom igen egyszerű a megoldása)
Az inputstreamből szeretnék adatot beolvasni, majd int-té konvertálni, a gondom viszont az, hogy overflownál kivételt kéne dobnom amire eleddig nem jöttem rá, hogyan kell, mármint hogy dönthetem el, hogy volt-e.
Előre is köszi a segítséget...

Hozzászólások

pont akkora mennyiséget olvass be, mint amekorra egy int:)

Ha jól értem: input stream -> char buffer (pl: scanf), char buffer -> integer (pl: atoi). Az atoi nem végez hibakezelést. http://linux.die.net/man/3/atoi
Ha csak ennyi a problémád, ezernyi megoldás van.

Egyébként másold be a kódot, úgy könnyebb megérteni mit is szeretnél. :)

Bár azt írtad, hogy probléma megoldva, azért hadd szóljak még hozzá, mert a kérdés az egyik kedvenc vesszőparipám :)

Először is azt javasolnám, hogy ne keverd a C-s és C++-os módszert. A C++ nem C. Igen, persze, "elérhető" benne a C; azonban annyira más a stílusuk, hogy nagyon nem hasznos a kettőt vegyíteni. Én legalábbis éles határt vonnék itt a (userspace) libc függvények és a syscall-ok között. Nyilván syscall-ok helyett nem tudsz mit használni (amelyek a man 2. fejezetében vannak), a man 3. fejezete helyett viszont használj tisztán C++-t.

Ennyi üres locsogás után nézzünk konkrétumot, bővebben lásd pl. innen indulva:


#include <iostream>

using namespace std;

int
main()
{
  int i;

  // manual check
  cin.clear();
  cin >> i;
  if (!cin.good()) {
    cerr << "failure detected in manual check\n";
    return 1;
  }

  // with exceptions -- clear control state before setting up exception mask
  // so that no exception is thrown immediately
  cin.clear();
  cin.exceptions(istream::eofbit | istream::failbit | istream::badbit);
  try {
    cin >> i;
  }
  catch (ios_base::failure& e) {
    cerr << "failure detected via exception\n";
    return 1;
  }
}

Első hiba:


2147483648
failure detected in manual check

Második hiba:


2147483647
2147483648
failure detected via exception

C-ben a következő függvényhez hasonlót szeretek használni (lásd strtol()):


#define _XOPEN_SOURCE 600

#include <stdlib.h> /* strtol() */
#include <errno.h>  /* errno */
#include <limits.h> /* INT_MIN */
#include <stdio.h>  /* fprintf() */

static int
long_parse(long *dest, const char *src, long min, long max)
{
  char *endptr;
  
  errno = 0;
  *dest = strtol(src, &endptr, 10);
  return ('\0' != *src && '\0' == *endptr && 0 == errno
      && min <= *dest && *dest <= max) ? 0 : -1;
}

int
main(int argc, char **argv)
{
  while (0 != *++argv) {
    long tmp;

    if (-1 == long_parse(&tmp, *argv, INT_MIN, INT_MAX)) {
      (void)fprintf(stderr, "unable to parse \"%s\" as an int\n", *argv);
    }
    else {
      int i;

      i = tmp;
      (void)fprintf(stdout, "\"%s\" parsed as int %d\n", *argv, i);
    }
  }

  return EXIT_SUCCESS;
}

Futtatva:


$ ./proba2 \
  '' \
  ' ' \
  '1 ' \
  ' 1' \
  a \
  9223372036854775808 \
  2147483648 \
  2147483647 \
  -2147483648 \
  -2147483649
unable to parse "" as an int
unable to parse " " as an int
unable to parse "1 " as an int
" 1" parsed as int 1
unable to parse "a" as an int
unable to parse "9223372036854775808" as an int
unable to parse "2147483648" as an int
"2147483647" parsed as int 2147483647
"-2147483648" parsed as int -2147483648
unable to parse "-2147483649" as an int

Nézzük, mit melyik részfeltétel nem teljesüléséért utasított el (miért úgy néz ki a

long_parse()

, ahogy):

  • "a"

    : a "subject sequence" (ld. fenti linket) üres, ezért nincs konverzió. Ekkor a visszaadott érték 0, az

    endptr

    a sztring elejére mutat, az

    errno

    -nak viszont nem kötelező

    EINVAL

    -t felvennie. Így ezt az esetet a

    '\0' == *endptr

    részfeltétel fogja meg.

  • " "

    : ugyanaz az eset, mint

    "a"

    , lásd fent.

  • ""

    : ugyanaz az eset, mint

    "a"

    , lásd fent, azzal a csúnya kiegészítéssel, hogy a sztring eleje, ahova az

    endptr

    mutat, egyből a vége is, ezért ezt a

    '\0' != *src

    fogja meg.

  • "1 "

    :

    '\0' == *endptr
  • "9223372036854775808"

    :

    0 == errno
  • "2147483648"

    :

    *dest <= max
  • "-2147483649"

    :

    min <= *dest

Miért kell az

errno = 0;

az egész elé: ha az

strtol()

nem állítja be -- lásd például sikeres parse-olásnál -- valamilyen értékre az

errno

-t, akkor az értékadás nélkül az

errno

értéke a

0 == errno

vizsgálatban meghatározatlan lehetne.

Ez a long_parse azert is jo, mert a strtol ele be lehet lokdosni olyasmiket is, hogy peldaul a whitespace karaktereket porgesse ki a sztringbol, igy parsolhatova valnak olyan stringek is, amik alapbol nem (pl a " 1" es a "1 " is).
--


()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.