Created
June 7, 2015 22:04
-
-
Save lpereira/06d980bbb3828090f9dd to your computer and use it in GitHub Desktop.
Number parsing using C11 _Generic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* parse_number() using C11 _Generic */ | |
/* @lafp, 2015-06-07 */ | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <errno.h> | |
#define parse_number(Input, Output) \ | |
_Generic((*Output), \ | |
int: parse_number_strtoint, \ | |
unsigned int: parse_number_strtouint, \ | |
long: parse_number_strtol, \ | |
long long: parse_number_strtoll, \ | |
unsigned long: parse_number_strtoul, \ | |
unsigned long long: parse_number_strtoull, \ | |
float: parse_number_strtof, \ | |
double: parse_number_strtod, \ | |
long double: parse_number_strtold)(Input, Output) | |
#define DECLARE_INT_PARSE_FN(Type, ParseFn) \ | |
bool \ | |
parse_number_ ## ParseFn(const char *input, Type *output) \ | |
{ \ | |
char *endptr = NULL; \ | |
errno = 0; \ | |
*output = ParseFn(input, &endptr, 0); \ | |
return errno == 0 && endptr && *endptr == '\0'; \ | |
} | |
int | |
strtoint(const char *input, char **endptr, int base) | |
{ | |
if (sizeof(int) == sizeof(long long)) { | |
long long output = strtoll(input, endptr, base); | |
if ((long long)(int)output != output) | |
errno = ERANGE; | |
return (int)output; | |
} | |
long output = strtol(input, endptr, base); | |
if ((long)(int)output != output) | |
errno = ERANGE; | |
return (int)output; | |
} | |
unsigned int | |
strtouint(const char *input, char **endptr, int base) | |
{ | |
if (sizeof(unsigned int) == sizeof(unsigned long long)) { | |
unsigned long long output = strtoull(input, endptr, base); | |
if ((unsigned long long)(unsigned int)output != output) | |
errno = ERANGE; | |
return (unsigned int)output; | |
} | |
unsigned long output = strtoul(input, endptr, base); | |
if ((unsigned long)(unsigned int)output != output) | |
errno = ERANGE; | |
return (unsigned int)output; | |
} | |
DECLARE_INT_PARSE_FN(long, strtol) | |
DECLARE_INT_PARSE_FN(long long, strtoll) | |
DECLARE_INT_PARSE_FN(unsigned long, strtoul) | |
DECLARE_INT_PARSE_FN(unsigned long long, strtoull) | |
DECLARE_INT_PARSE_FN(int, strtoint) | |
DECLARE_INT_PARSE_FN(unsigned int, strtouint) | |
#undef DECLARE_INT_PARSE_FN | |
#define DECLARE_FLOAT_PARSE_FN(Type, ParseFn) \ | |
bool \ | |
parse_number_ ## ParseFn(const char *input, Type *output) \ | |
{ \ | |
char *endptr = NULL; \ | |
errno = 0; \ | |
*output = ParseFn(input, &endptr); \ | |
return errno == 0 && endptr && *endptr == '\0'; \ | |
} | |
DECLARE_FLOAT_PARSE_FN(float, strtof) | |
DECLARE_FLOAT_PARSE_FN(double, strtod) | |
DECLARE_FLOAT_PARSE_FN(long double, strtold) | |
#undef DECLARE_FLOAT_PARSE_FN | |
int | |
main(void) | |
{ | |
long loutput; | |
long long lloutput; | |
unsigned long uloutput; | |
unsigned long long ulloutput; | |
size_t soutput; | |
int ioutput; | |
unsigned int uioutput; | |
float foutput; | |
double doutput; | |
long double ldoutput; | |
if (!parse_number("0", &loutput)) | |
return 1; | |
if (!parse_number("0", &lloutput)) | |
return 1; | |
if (!parse_number("0", &uloutput)) | |
return 1; | |
if (!parse_number("0", &ulloutput)) | |
return 1; | |
if (!parse_number("0", &soutput)) | |
return 1; | |
if (!parse_number("0", &ioutput)) | |
return 1; | |
if (!parse_number("0", &uioutput)) | |
return 1; | |
if (!parse_number("0", &foutput)) | |
return 1; | |
if (!parse_number("0", &doutput)) | |
return 1; | |
if (!parse_number("0", &ldoutput)) | |
return 1; | |
printf("done!\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment