开发者

How to stop double automatic conversion on overflow?

I have a code in which i am extracting strings from environment using getenv, parsing them into numbers using strtod. If user enters, 213.123. Then 213 and 123 will be individually fed to a long type.

long a1 = 213; long a2 = 123

The problem i am facing is, if user enters a very long number like: 123456789123.45678, it is automatically getting rounded off, which i don't want and instead throw an error, however ERANGE isn't working.

9 static  volatile int flag;                   /* flag variable to indicate when the measurement should start */
10 static  time_t       ef_errtrack_start_sec;  /* error track start time in seconds */
11 static  long         e开发者_如何学Gof_errtrack_start_nsec; /* error track start time in nanoseconds */
12 static  time_t       ef_errtrack_end_sec;    /* error track end time in seconds */
13 static  long         ef_errtrack_end_nsec;   /* error track end time in nanoseconds */

21 int main(int argc, char **argv)
22 {
23     extractTime(1); /* Extracting start time */
24     extractTime(0); /* Extracting end time   */
25 
26     printf("start: %12d, %12d\n", ef_errtrack_start_sec, ef_errtrack_start_nsec);
27     printf("end:   %12d, %12d\n", ef_errtrack_end_sec,   ef_errtrack_end_nsec);
28 
29     return 0;
30 }


35 void extractTime(int extractStartTime)
36 {
37         char * charPtr, * numberFormatErr;
38         regex_t re;
39 
40         ( extractStartTime == 1 ) ? ( charPtr = getenv("EF_ERRTRACK_START") ) :
41                 ( charPtr = getenv("EF_ERRTRACK_END") );
42 
43         if ( charPtr == NULL )
44                 return;
45 
46         double envVal = strtod(charPtr, &numberFormatErr);
47 
48         if ( (numberFormatErr == charPtr) || (*numberFormatErr != '\0') ) {
49                 ( extractStartTime == 1 ) ? printf("eFence exited: EF_ERRTRACK_START is not a number\n") :
50                         printf("eFence exited: EF_ERRTRACK_END is not a number\n");
51                 exit(1);
52         }
53         if ( errno == ERANGE )
54         {
55                 ( extractStartTime == 1 ) ? EF_Print("eFence exited: EF_ERRTRACK_START is out of range\n") :
56                         EF_Print("eFence exited: EF_ERRTRACK_END is out of range\n");
57                 exit(1);
58         }
59         else if ( envVal < 0 ) {
60                 ( extractStartTime == 1 ) ? printf("eFence exited: EF_ERRTRACK_START a negative number\n") :
61                         printf("eFence exited: EF_ERRTRACK_END is a negative number\n");
62                 exit(1);
63         }
64 
65         if ( extractStartTime ) {
66                 ef_errtrack_start_sec = envVal;
67                 double nsec = (envVal) - (double)(ef_errtrack_start_sec);
68                 ef_errtrack_start_nsec = (long)(nsec * 1000000000);
69         }
70         else {
71                 ef_errtrack_end_sec = envVal;
72                 double nsec = (envVal) - (double)(ef_errtrack_end_sec);
73                 ef_errtrack_end_nsec = (long) (nsec * 1000000000);
74         }
75 }

Here is the output:

Output:
/tmp # export EF_ERRTRACK_START=1234567891234.123456789123
/tmp # export EF_ERRTRACK_END=10e2

/tmp/time_related # ./a.out 

start:   2147483647,   2147483647
end:           1000,            0


"Outside the range of representable values" means bigger than DBL_MAX. Your input is in range, it just isn't exactly representable as a double.

For that matter, 0.1 is also in range, and also isn't exactly representable. Should that also be an error, and if not, what's the difference?

I'm not sure what to advise you to do, because I'm not sure why you consider your case an error. One option would be that once you have your double, convert it back to string with snprintf and compare to the original input, see whether they are equal at least as far as the decimal point. That ignores scientific notation, though, so there may be more work required to identify the numbers you don't like.

Edit: ah, initially I didn't really assimilate this: "If user enters, 213.123. Then 213 and 123 will be individually fed to a long type."

Sounds like what you are reading is not a double value, it's two integer values separated by a period character. So don't use strtod, find the . and then call strtol on each side of it.


I think you have to parse the input, identify the possible types (and errors) and act accordingly (no double necessary)

if input has no '.' and no 'e' then secs = input; nano = 0;
if input has '.' and no 'e' then secs = firstpart; nano = secondpart (scaled appropriately)
if input has no '.' but has 'e' then convert into the 1st or 2nd format above
if input has '.' and 'e' then convert into the 1st or 2nd format above
if input has '.' after 'e' then give error
if input has 2 or more '.' then give error
if input has 2 or more 'e' then give error
... something else I didn't think about
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜