How can I check if a string can be converted to a

2020-03-26 19:40发布

First my context is that of a compiler writer who needs to convert floating point literals (strings) into float/double values. I haven't done any floating point programming the last 15 years so i'm pretty sure this is a total stupid newbie question.

double res; 
errno=0; 
*res = strtod((const char*)literal,NULL); 
if (errno==ERANGE) throw_a_literal_out_of_range_exception();
return res;

but there is no "strtof" function in the c runtime library?

EDIT: To clarify. I already know that the string 'literal' is a valid pattern for a C floating point. It already passed a regular expression test. I just want to check if there is a range/precision problem.

The reason is in Eiffel source code a user can write

a := {REAL_32} 3.1415
b := {REAL_32} 3.0E200

To cast a written floating point number explit to a 32bit floating point. I think in the second case the compiler should detect that the value is out of range and raise an error or at least a warning.

7条回答
来,给爷笑一个
2楼-- · 2020-03-26 19:55

In C89 you may use sscanf.

For example:

float myfloat;

if(sscanf(str, "%f", &myfloat) != 1)
    /* String could not be converted */
else
    /* String was converted, myfloat is usable */
查看更多
对你真心纯属浪费
3楼-- · 2020-03-26 19:59

strtof does not exist in C89, but it does in C99.

查看更多
The star\"
4楼-- · 2020-03-26 20:01

On MSVC you can use _atoflt(), defined in stdlib.h

查看更多
smile是对你的礼貌
5楼-- · 2020-03-26 20:02

I suggest converting to double first, then cast to float. If the relative difference, (f-d)/f, is greater than float precision (roughly, 1e-7) then there are more digits than what can be safely stored in float.

查看更多
一纸荒年 Trace。
6楼-- · 2020-03-26 20:03

Since you have your value in a double, you can just check if it's outside of the range of float:

#include <stdlib.h>
#include <stdio.h>
#include <float.h>

int main(int argc, char *argv[])
{
    double d = FLT_MAX;
    if (argc > 1) {
        d = strtod(argv[1], NULL);
    }
    if ((d > 0 && (d > FLT_MAX || d < FLT_MIN))
                || (d < 0 && (d < -FLT_MAX || d > -FLT_MIN)))
        printf("Invalid float: %g\n", d);
    else
        printf("Valid: %g\n", d);

    return EXIT_SUCCESS;
}

Running the program:

$ ./a.out
Valid: 3.40282e+38
$ ./a.out 3.5e38
Invalid float: 3.5e+38
$ ./a.out -1e40
Invalid float: -1e+40

You may or may not need to add a test for correct strtod() return, depending upon whether there's a possibility of an overflow in double type as well.

查看更多
我只想做你的唯一
7楼-- · 2020-03-26 20:16

@Nicholas Goy: I don't think sscanf(str, "%f, &float) == 1 (or != 1) really does what's desired.

If there are additional characters in str (e.g. "1.1foo"), it will parse without error, which is probably undesirable. This can be rectified by doing:

char dummy;
if (sscanf(str, "%f%c", &float, &dummy) != 1) {
   /* Parse error. */
} else {
   /* Parsed cleanly. */
}

instead. However, sscanf with %f is likely to use strtod internally and cast to float anyway. The language in the C standard says:

a,e,f,g Matches an optionally signed floating-point number, infinity, or NaN, whose format is the same as expected for the subject sequence of the strtod function. The corresponding argument shall be a pointer to floating.

which sort of implies this, and it seems to be true for me (gcc 4.2.1 on FreeBSD). Using the above sscanf code, "1.79e308" parses successfully but has the value +inf, as does "5e-300" with the value 0.0, and these are the same results you'd get from (float) 1.79e308 and (float) 5e-300.

Anyway. All that said, I question why the OP wants to use float instead of double anyway.

查看更多
登录 后发表回答