Программа Number Parser: почему strtol / strtod не работает для экспоненциальных и шестнадцатеричных чисел - PullRequest
1 голос
/ 20 сентября 2011

Я написал небольшой код, который разбивает любую строку (экспортированную как переменную среды) на целое число и дробную часть.

Пример: экспорт ENV_NUM = 3.45

Программа напечатает: целое число: 3 Дробное: 0,45

Кроме того, эта программа также сканирует, находится ли экспортированный номер вне допустимого диапазона или является недопустимым, и в этом случае она прекращает печать сообщения об ошибке.

Чтобы упростить для читателя вещи, позвольте мне объяснить логику, которую я использовал : я отсканировал число и число разбилось на 2 части, используя strtok, где бы он ни находил десятичную дробь (.), А затем назначал первоетокен для целой части и следующий токен для дробной части.

Проблема, с которой столкнулся : Теперь проблема с этой программой: она дает ошибочные результаты, если экспортируемое число является шестнадцатеричным или экспоненциальнымчисло.

Можете ли вы сообщить мне, в чем проблема?

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <string.h>


static  time_t       wholeNumber;  
static  float        fractional; 

void numberParser(void);

int main(int argc, char **argv)
{
 numberParser( ); 
 printf("Whole number: %12d, Fractional: %5.8f\n", wholeNumber, fractional);
 return 0;
}

void numberParser( void )
 {
     char * charPtr, * numberFormatErr;
     charPtr = getenv("ENV_NUM"); 

     if ( charPtr == NULL )
            return;

     double envVal = strtod(charPtr, &numberFormatErr);

     /* This part checks if the string is a valid number and not negative */

     if ( (numberFormatErr == charPtr) || (*numberFormatErr != '\0') ) {
            printf("exited: ENV_NUM is not a number\n");
            exit(1);
     }
     else if ( envVal < 0 ) {
            printf("exited: ENV_NUM a negative number\n");
            exit(1);
     }

     /* This part breaks the string into integral and float part */

     char * tokens = strtok(charPtr, ".");
     int count = 0;
errno = 0;

     while ( tokens != NULL ) {
    //printf("Token scanned: %s\n",tokens);
            long d = strtol(tokens, NULL, 10);
    //printf("token to long: %5d\n",d);

            if ( errno == ERANGE && d == LONG_MAX ) {
                   printf("exited: ENV_NUM not in valid range.");
                   exit(1);
            }

            if ( count == 0 ) {
                    ( wholeNumber = d );
            }

            tokens = strtok(NULL, " ");
                    count++;
       }
            fractional = (envVal) - (double)(wholeNumber);
   }

Вот вывод:

Correct output for normal numbers
[time_related]$ ./a.out 
Whole number:    3, Fractional: 0.56000000

Неверный вывод для шестнадцатеричного числа: [time_related] $ export ENV_NUM = 0x21

[time_related]$ ./a.out 
Whole number:  0, Fractional: 33.00000000 (should be 33, 0)

Неверный вывод для экспоненты: [time_related] $ export ENV_NUM = 3e3

[time_related]$ ./a.out 
Whole number:            3, Fractional: 2997.00000000 (should be 3000, 0)

Ответы [ 2 ]

0 голосов
/ 20 сентября 2011
#include <stdio.h>
#include <stdlib.h>

double numberParser(char *str){
    double val;
    long  lval;
    char *p;

    val=strtod(str, &p);//exponential number OK!, 0x prefix from C99
    if(*p == '\0')
        return val;
    else if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X')){
        lval = strtol(str, &p, 16);//strtol(str, &p, 0) better
        if(*p == '\0')
            return (double)lval;
    }
    return -1.0;//error
}

int main(int argc, char **argv){
    double wk;
    int i;

    i= wk = numberParser("3.45");
    printf("Whole number: %12d, Fractional: %5.8f\n", i, wk - i); 

    i= wk = numberParser("0x21");
    printf("Whole number: %12d, Fractional: %5.8f\n", i, wk - i); 

    i= wk = numberParser("3e3");
    printf("Whole number: %12d, Fractional: %5.8f\n", i, wk - i); 

    return 0;
}

вывод:

Whole number:            3, Fractional: 0.45000000
Whole number:           33, Fractional: 0.00000000
Whole number:         3000, Fractional: 0.00000000
0 голосов
/ 20 сентября 2011

Я удивлен, что strtod анализирует шестнадцатеричные числа, так как я посмотрел две ссылки, и они не упоминают такую ​​возможность, но почему бы и нет.
Обратите внимание, что 0x21 = 33, а не 35.

Высделал промежуточную печать, используйте его: для 0x21 envVal равен 33, strtol не может выполнить синтаксический анализ за пределами x, поэтому он возвращает 0, а дробный - envVal - 0 = 33
То же самое для 3e3: это не длинное число,так что strtol возвращает 3, а дробное - 3000-3

. Вы должны добавить проверку результата strtol, как вы это сделали для strtod ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...