如何在溢出时停止双重自动转换?

时间:2011-09-26 11:18:15

标签: c linux double long-integer

我有一个代码,我使用getenv从环境中提取字符串,使用strtod将它们解析为数字。 如果用户输入,213.123。然后将213和123单独送入长型。

long a1 = 213; long a2 = 123

我面临的问题是,如果用户输入一个非常长的数字,如:123456789123.45678,它会自动四舍五入,这是我不想要的,而是抛出错误,但是ERANGE无法正常工作。

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         ef_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 }

这是输出:

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

2 个答案:

答案 0 :(得分:3)

“超出可表示值的范围”意味着大于DBL_MAX。您的输入在范围内,它不能完全表示为双精度。

就此而言,0.1也在范围内,也不完全可以表示。这也应该是一个错误,如果不是,那有什么区别?

我不确定建议你做什么,因为我不确定为什么你认为你的情况是错误的。一种选择是,一旦你有了double,将它转换回snprintf的字符串并与原始输入进行比较,看看它们是否至少等于小数点。但是,这忽略了科学记数法,因此可能需要做更多的工作来确定你不喜欢的数字。

编辑:啊,最初我并没有真正吸收这个:“如果用户输入,213.123。那么213和123将被单独输入一个长类型。”

听起来你正在阅读的不是一个双精度值,它是由句点字符分隔的两个整数值。因此,请勿使用strtod,找到.,然后在其两侧调用strtol

答案 1 :(得分:0)

我认为你必须解析输入,识别可能的类型(和错误)并采取相应的行动(不需要double

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