In C (not in C++), I would use a combination of strtod/strol and max values from <limits.h> and <float.h>:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <float.h>
/* Now, we know the following values:
INT_MAX, INT_MIN, SHRT_MAX, SHRT_MIN, CHAR_MAX, CHAR_MIN, etc. */
typedef union tagMyUnion
{
char TChar_ ; short TShort_ ; long TLong_ ; double TDouble_ ;
} MyUnion ;
typedef enum tagMyEnum
{
TChar, TShort, TLong, TDouble, TNaN
} MyEnum ;
void whatIsTheValue(const char * string_, MyEnum * enum_, MyUnion * union_)
{
char * endptr ;
long lValue ;
double dValue ;
*enum_ = TNaN ;
/* integer value */
lValue = strtol(string_, &endptr, 10) ;
if(*endptr == 0) /* It is an integer value ! */
{
if((lValue >= CHAR_MIN) && (lValue <= CHAR_MAX)) /* is it a char ? */
{
*enum_ = TChar ;
union_->TChar_ = (char) lValue ;
}
else if((lValue >= SHRT_MIN) && (lValue <= SHRT_MAX)) /* is it a short ? */
{
*enum_ = TShort ;
union_->TShort_ = (short) lValue ;
}
else if((lValue >= LONG_MIN) && (lValue <= LONG_MAX)) /* is it a long ? */
{
*enum_ = TLong ;
union_->TLong_ = (long) lValue ;
}
return ;
}
/* real value */
dValue = strtod(string_, &endptr) ;
if(*endptr == 0) /* It is an real value ! */
{
if((dValue >= -DBL_MAX) && (dValue <= DBL_MAX)) /* is it a double ? */
{
*enum_ = TDouble ;
union_->TDouble_ = (double) dValue ;
}
return ;
}
return ;
}
void studyValue(const char * string_)
{
MyEnum enum_ ;
MyUnion union_ ;
whatIsTheValue(string_, &enum_, &union_) ;
switch(enum_)
{
case TChar : printf("It is a char : %li\n", (long) union_.TChar_) ; break ;
case TShort : printf("It is a short : %li\n", (long) union_.TShort_) ; break ;
case TLong : printf("It is a long : %li\n", (long) union_.TLong_) ; break ;
case TDouble : printf("It is a double : %f\n", (double) union_.TDouble_) ; break ;
case TNaN : printf("It is a not a number : %s\n", string_) ; break ;
default : printf("I really don't know : %s\n", string_) ; break ;
}
}
int main(int argc, char **argv)
{
studyValue("25") ;
studyValue("-25") ;
studyValue("30000") ;
studyValue("-30000") ;
studyValue("300000") ;
studyValue("-300000") ;
studyValue("25.5") ;
studyValue("-25.5") ;
studyValue("25555555.55555555") ;
studyValue("-25555555.55555555") ;
studyValue("Hello World") ;
studyValue("555-55-55") ;
return 0;
}
Which results in the following:
[25] is a char : 25
[-25] is a char : -25
[30000] is a short : 30000
[-30000] is a short : -30000
[300000] is a long : 300000
[-300000] is a long : -300000
[25.5] is a double : 25.500000
[-25.5] is a double : -25.500000
[25555555.55555555] is a double : 25555555.555556
[-25555555.55555555] is a double : -25555555.555556
[Hello World] is a not a number
[555-55-55] is a not a number
Sorry for my rusty C.
:-)
So, in substance, you after the call of whatIsTheValue, you retrieve the type through the MyEnum enum, and then, according to the value in this enum, retrieve the right value, correctly typed, from the union MyUnion.
Note that finding if the number is a double or a float is a bit more complicated because the difference seems to be in the precision, i.e. is your number representable in a double, or in float. A most "decimal real" numbers are not exactly representable into a double, I would not bother.
Note, too, that there is a catch, as 25.0 could be both real and an integer number. My comparing "dValue == (double)(long)dValue", I guess you should know if is an integer, again, not taking into account the usual precision problems coming witb binary real numbers used by computers.