Safely convert Strings to Number strtoX functions
suggest changeSince C99 the C library has a set of safe conversion functions that interpret a string as a number. Their names are of the form strtoX
, where X
is one of l
, ul
, d
, etc to determine the target type of the conversion
double strtod(char const* p, char** endptr); long double strtold(char const* p, char** endptr);
They provide checking that a conversion had an over- or underflow:
double ret = strtod(argv[1], 0); /* attempt conversion */ /* check the conversion result. */ if ((ret == HUGE_VAL || ret == -HUGE_VAL) && errno == ERANGE) return; /* numeric overflow in in string */ else if (ret == HUGE_VAL && errno == ERANGE) return; /* numeric underflow in in string */ /* At this point we know that everything went fine so ret may be used */
If the string in fact contains no number at all, this usage of strtod
returns 0.0
.
If this is not satisfactory, the additional parameter endptr
can be used. It is a pointer to pointer that will be pointed to the end of the detected number in the string. If it is set to 0
, as above, or NULL
, it is simply ignored.
This endptr
parameter provides indicates if there has been a successful conversion and if so, where the number ended:
char *check = 0; double ret = strtod(argv[1], &check); /* attempt conversion */ /* check the conversion result. */ if (argv[1] == check) return; /* No number was detected in string */ else if ((ret == HUGE_VAL || ret == -HUGE_VAL) && errno == ERANGE) return; /* numeric overflow in in string */ else if (ret == HUGE_VAL && errno == ERANGE) return; /* numeric underflow in in string */ /* At this point we know that everything went fine so ret may be used */
There are analogous functions to convert to the wider integer types:
long strtol(char const* p, char** endptr, int nbase); long long strtoll(char const* p, char** endptr, int nbase); unsigned long strtoul(char const* p, char** endptr, int nbase); unsigned long long strtoull(char const* p, char** endptr, int nbase);
These functions have a third parameter nbase
that holds the number base in which the number is written.
long a = strtol("101", 0, 2 ); /* a = 5L */ long b = strtol("101", 0, 8 ); /* b = 65L */ long c = strtol("101", 0, 10); /* c = 101L */ long d = strtol("101", 0, 16); /* d = 257L */ long e = strtol("101", 0, 0 ); /* e = 101L */ long f = strtol("0101", 0, 0 ); /* f = 65L */ long g = strtol("0x101", 0, 0 ); /* g = 257L */
The special value 0
for nbase
means the string is interpreted in the same way as number literals are interpreted in a C program: a prefix of 0x
corresponds to a hexadecimal representation, otherwise a leading 0
is octal and all other numbers are seen as decimal.
Thus the most practical way to interpret a command-line argument as a number would be
int main(int argc, char* argv[] { if (argc < 1) return EXIT_FAILURE; /* No number given. */ /* use strtoull because size_t may be wide */ size_t mySize = strtoull(argv[1], 0, 0); /* then check conversion results. */ ... return EXIT_SUCCESS; }
This means that the program can be called with a parameter in octal, decimal or hexadecimal.