In C (nicht in C++) würde ich eine Kombination von strtod/strol und max-Werten aus <limits.h> und <float.h> verwenden:
#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;
}
Daraus ergibt sich das Folgende:
[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
- Entschuldigung für mein eingerostetes C.
-)
Im Wesentlichen wird also nach dem Aufruf von whatIsTheValue der Typ über das Enum MyEnum abgerufen, und dann wird entsprechend dem Wert in diesem Enum der richtige, korrekt typisierte Wert aus der Union MyUnion abgerufen.
Die Feststellung, ob es sich bei der Zahl um ein Double oder ein Float handelt, ist etwas komplizierter, denn der Unterschied scheint in der Genauigkeit zu liegen, d. h. ob die Zahl als Double oder als Float darstellbar ist. Die meisten "dezimalen reellen" Zahlen lassen sich nicht genau als Double darstellen, daher würde ich mir die Mühe nicht machen.
Beachten Sie auch, dass es einen Haken gibt, da 25,0 sowohl eine reelle als auch eine ganzzahlige Zahl sein kann. Wenn ich "dValue == (double)(long)dValue" vergleiche, sollten Sie wissen, ob es sich um eine ganze Zahl handelt, wobei die üblichen Präzisionsprobleme bei binären reellen Zahlen, die von Computern verwendet werden, unberücksichtigt bleiben.