:이 기능은 선택적 소수점 및 선택적 지수 지정자 ("E"또는 "E")와 숫자 문자열을 구문 분석합니다. 필자는 임의의 정밀도 라이브러리를 수정하고 여전히 천박한 혼란스러운 것 중 하나는 문자열 파싱이므로, 제한된 상태 머신을 설정하고 (적절한 단축키를 사용하여) 적절하게 구현했다. 거의 500 줄의 코드. 나는 단순한 'double'을 테스트 용으로 사용했다. (사용하지 않고 에러가 너무 크다!) 몇 가지 간단한 테스트를 할 수있다.
동일한 이진 지수 및 지수 마커 p
을 표준화 된 16 진수 숫자로 사용하면 8 진수도 허용한다는 점에 유의하십시오. strtod
은 인정하지 않습니다.
오, 나는 꽤 버그가 있다는 것을 확신합니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// for pow() only
#include <math.h>
#ifdef DEBUG
# define PUTS(x) puts(x)
#else
# define PUTS(x)
#endif
#define FSM_OK 1
#define FSM_ERROR 0
/*
EBNF (ISO 14977) for the real numbers this code should be able to treat correctly.
(* sign *)
sign = '+'|'-';
(* numbers starting with zero are octal, hence the special treatment for zero *)
zero = '0';
(* binary digit *)
bindig = '1';
(* binary integer *)
binint = bindig , [{(zero | bindig)}];
(* octal digit *);
octdig = bindig|'2'|'3'|'4'|'5'|'6'|'7';
(* octal integer *)
octint = octdig , [{(zero | octdig)}];
(* decimal digit *)
decdig = octdig|'8'|'9';
(* decimal integer *)
decint = decdig , [{(zero | decdig)}];
(* hexadecimal digit *)
hexdig = decdig |'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'e'|'f';
(* hexadecimal integer *)
hexint = hexdig , [{(zero | hexdig)}];
(* prefix for the base; inclusion of octal numbers made it interesting *)
prefix = '0';
(* Implementing only the four main bases has been deemed sufficient *)
binbase = prefix , ('B'|'b');
octbase = prefix , octdig;
hexbase = prefix , ('X'|'x');
(* decimal point *)
decpoint = '.';
(* exponents *)
expobin = ('P'|'p'), [sign], decint;
expodec = ('E'|'e'), [sign], decint;
(* thousands separator *)
(* tsep = ','|'\''|'_'; *)
(* "xyz", "xyz.", "xyz.zyx", ".zyx" *)
stubrealbin = binint | (binint, decpoint, [binint]) | (decpoint, binint);
stubrealoct = octint | (octint, decpoint, [octint]) | (decpoint, octint);
stubrealdec = decint | (decint, decpoint, [decint]) | (decpoint, decint);
stubrealhex = hexint | (hexint, decpoint, [hexint]) | (decpoint, hexint);
fullrealbin = [sign], binbase, stubrealbin, [expobin];
fullrealoct = [sign], octbase, stubrealoct, [expobin];
fullrealdec = [sign], stubrealdec, [expodec];
fullrealhex = [sign], hexbase, stubrealhex, [expobin];
(* "InF" and "NaN" should be case insensitive in praxi *)
real = ([sign], "Inf") | "NaN" | fullrealbin | fullrealoct | fullrealdec | fullrealhex;
Input characters (grouped for clarity. Case sensitive for brevity only!).
The input is case insensitive, so 'e', 'E', 'b', and 'B' are only
distinguishable by context: once you have hexdigits 'e' and 'b' are hexdigits
and a following sign must trigger an error
'0'
'1' = bin
'2'|'3'|'4'|'5'|'6'|'7' = oct
'8'|'9' = dec
'A'| |'C'|'D' |'F' = hex
'x'
'b'
'e'
'p'
'.'
'+' | '-' = sgn
Any other input character is not valid (state: ERROR), "Inf" and "NaN" get handled
elsewhere to keep things simple.
States
START
SIGN
PREFIX
DECPOINT
DECFRAC
BINBASE
OCTBASE
DECBASE
HEXBASE
BINFRAC
OCTFRAC
HEXFRAC
EXPOMARK
EXPOSIGN
EXPONENT
ERROR
Transition table
START '0' it is a prefix PREFIX
bin it is a binary digit DECBASE
oct it is an octal digit DECBASE
dec it is a decimal digit DECBASE
hex it is a hexadecimal digit HEXBASE
'x' cannot be ERROR
'b' it is a hexadecimal digit HEXBASE
'e' it is a hexadecimal digit HEXBASE
'p' cannot be ERROR
'.' a decimal point DECPOINT (!)
sgn a sign SIGN
SIGN '0' it is a prefix PREFIX
bin it is a binary digit DECBASE
oct it is an octal digit DECBASE
dec it is a decimal digit DECBASE
hex it is a hexadecimal digit HEXBASE
'x' cannot be ERROR
'b' it is a hexadecimal digit HEXBASE
'e' it is a hexadecimal digit HEXBASE
'p' cannot be ERROR
'.' a decimal point DECPOINT (!)
sgn a sign ERROR
PREFIX '0' zero OCTBASE
bin binary digit OCTBASE
oct octal digit OCTBASE
dec cannot be ERROR
hex cannot be ERROR
'x' hexadecimal number HEXBASE
'b' binary number BINBASE
'e' cannot be ERROR
'p' cannot be ERROR
'.' decimal point DECFRAC
sgn cannot be ERROR
The only place, that is still lingering in limbo is the decimal point. We
need to fork again, but we do not know in which base the integral part (if one
exists at all) is, so we still take "decimal" to be the default base.
DECPOINT '0' binary digit DECFRAC
bin binary digit DECFRAC
oct octal digit DECFRAC
dec decimal digit DECFRAC
hex hexadecimal digit HEXFRAC
'x' cannot be ERROR
'b' hexadecimal digit HEXFRAC
'e' hexadecimal digit HEXFRAC
'p' binary exponent EXPOMARK
'.' decimal point ERROR
sgn cannot be ERROR
A fractional part in decimal base is simple enough
DECFRAC '0' binary digit DECFRAC
bin binary digit DECFRAC
oct octal digit DECFRAC
dec decimal digit DECFRAC
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' exponent delimiter EXPOMARK
'p' cannot be ERROR
'.' cannot be ERROR
sgn cannot be ERROR
All other fractions need a base, so handle bases first
BINBASE '0' binary digit BINBASE
bin binary digit BINBASE
oct cannot be ERROR
dec cannot be ERROR
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' exponent delimiter EXPOMARK
'.' decimal point BINFRAC
sgn cannot be ERROR
OCTBASE '0' binary digit OCTBASE
bin binary digit OCTBASE
oct octal digit OCTBASE
dec cannot be ERROR
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' exponent delimiter EXPOMARK
'.' decimal point OCTFRAC
sgn cannot be ERROR
HEXBASE '0' binary digit HEXBASE
bin binary digit HEXBASE
oct octal digit HEXBASE
dec decimal digit HEXBASE
hex hexadecimal digit HEXBASE
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' exponent delimiter EXPOMARK
'.' decimal point HEXFRAC
sgn cannot be ERROR
It is easy now to fill the gaps.
BINFRAC '0' binary digit BINFRAC
bin binary digit BINFRAC
oct cannot be ERROR
dec cannot be ERROR
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' exponent delimiter EXPOMARK
'.' cannot be ERROR
sgn cannot be ERROR
OCTFRAC '0' binary digit OCTFRAC
bin binary digit OCTFRAC
oct octal digit OCTFRAC
dec cannot be ERROR
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' exponent delimiter EXPOMARK
'.' cannot be ERROR
sgn cannot be ERROR
HEXFRAC '0' binary digit HEXFRAC
bin binary digit HEXFRAC
oct octal digit HEXFRAC
dec decimal digit HEXFRAC
hex hexadecimal digit HEXFRAC
'x' cannot be ERROR
'b' hexadecimal digit HEXFRAC
'e' hexadecimal digit HEXFRAC
'p' exponent delimiter EXPOMARK
'.' decimal point ERROR
sgn cannot be ERROR
The exponent is always encoded in decimal base (IEEE 754 (ISO/IEC 60559) sec. 5.12.3 for
the hexadecimal example)
EXPOMARK '0' binary digit EXPONENT
bin binary digit EXPONENT
oct octal digit EXPONENT
dec decimal digit EXPONENT
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' cannot be ERROR
'.' cannot be ERROR
sgn sign EXPOSIGN
EXPOSIGN '0' binary digit EXPONENT
bin binary digit EXPONENT
oct octal digit EXPONENT
dec decimal digit EXPONENT
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' cannot be ERROR
'.' cannot be ERROR
sgn sign ERROR
EXPONENT '0' binary digit EXPONENT
bin binary digit EXPONENT
oct octal digit EXPONENT
dec decimal digit EXPONENT
hex cannot be ERROR
'x' cannot be ERROR
'b' cannot be ERROR
'e' cannot be ERROR
'p' cannot be ERROR
'.' cannot be ERROR
sgn sign ERROR
ERROR nothing follows an error, only more ERROR
Nothing marking an end-state, it is just the end of the input buffer
ZERO '0'
BINDIG '1'
OCTDIG '2'|'3'|'4'|'5'|'6'|'7'
DECDIG '8'|'9'
HEXDIG 'A'| |'C'|'D' |'F'
PREHEX 'x'
PREBIN 'b'
EXPDEC 'e'
EXPBIN 'p'
DECPNT '.'
SGNCHR '+' | '-'
ZERO BINDIG OCTDIG DECDIG HEXDIG PREHEX PREBIN EXPDEC EXPBIN DECPNT SGNCHR
START PREFIX DECBASE DECBASE DECBASE HEXBASE ERROR HEXBASE HEXBASE ERROR DECPOINT SIGN
SIGN PREFIX DECBASE DECBASE DECBASE HEXBASE ERROR HEXBASE HEXBASE ERROR DECPOINT ERROR
PREFIX OCTBASE OCTBASE OCTBASE ERROR ERROR HEXBASE BINBASE ERROR ERROR DECFRAC ERROR
DECPOINT DECFRAC DECFRAC DECFRAC DECFRAC HEXFRAC ERROR HEXFRAC HEXFRAC EXPOMARK ERROR ERROR
DECFRAC DECFRAC DECFRAC DECFRAC DECFRAC ERROR ERROR ERROR EXPOMARK ERROR ERROR ERROR
BINBASE BINBASE BINBASE ERROR ERROR ERROR ERROR ERROR ERROR EXPOMARK BINFRAC ERROR
OCTBASE OCTBASE OCTBASE OCTBASE ERROR ERROR ERROR ERROR ERROR EXPOMARK OCTFRAC ERROR
DECBASE DECBASE DECBASE DECBASE ERROR ERROR ERROR ERROR EXPOMARK ERROR DECFRAC ERROR
HEXBASE HEXBASE HEXBASE HEXBASE HEXBASE HEXBASE ERROR ERROR ERROR EXPOMARK HEXFRAC ERROR
BINFRAC BINFRAC BINFRAC ERROR ERROR ERROR ERROR ERROR ERROR EXPOMARK ERROR ERROR
OCTFRAC OCTFRAC OCTFRAC OCTFRAC ERROR ERROR ERROR ERROR ERROR EXPOMARK ERROR ERROR
HEXFRAC HEXFRAC HEXFRAC HEXFRAC HEXFRAC HEXFRAC ERROR HEXFRAC HEXFRAC EXPOMARK ERROR ERROR
EXPOMARK EXPON'T EXPON'T EXPON'T EXPON'T ERROR ERROR ERROR ERROR ERROR ERROR EXPOSIGN
EXPOSIGN EXPON'T EXPON'T EXPON'T EXPON'T ERROR ERROR ERROR ERROR ERROR ERROR ERROR
EXPONENT EXPON'T EXPON'T EXPON'T EXPON'T ERROR ERROR ERROR ERROR ERROR ERROR ERROR
ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR
*/
#if !(defined _BSD_SOURCE || defined _DEFAULT_SOURCE || _POSIX_C_SOURCE >= 200112L)
# include <ctype.h>
static int strncasecmp(const char *s1, const char *s2, size_t n)
{
char c1 = 0;
char c2 = 0;
while (n--) {
c1 = tolower(*s1);
c2 = tolower(*s2);
if (c1 != c2) {
break;
}
if (c1 == '\0') {
break;
}
s1++;
s2++;
}
return (int) (c1 - c2);
}
#endif
#ifdef _MSC_VER
#define strncasecmp(x,y,z) _strnicmp(x,y,z)
#endif
enum fsm_input {
ZERO, // '0'
BINDIG, // '1'
OCTDIG, // '2'|'3'|'4'|'5'|'6'|'7'
DECDIG, // '8'|'9'
HEXDIG, // 'A' |'C'|'D' |'F'
PREHEX, // 'x'
PREBIN, // 'b'
EXPDEC, // 'e'
EXPBIN, // 'p'
DECPNT, // '.'
SGNCHR, // '+' | '-'
OTHER
};
enum fsm_states {
START,
SIGN,
PREFIX,
DECPOINT,
DECFRAC,
BINBASE,
OCTBASE,
DECBASE,
HEXBASE,
BINFRAC,
OCTFRAC,
HEXFRAC,
EXPOMARK,
EXPOSIGN,
EXPONENT,
ERROR
};
#ifdef DEBUG
static const char *st2str[16] = {
"START",
"SIGN",
"PREFIX",
"DECPOINT",
"DECFRAC",
"BINBASE",
"OCTBASE",
"DECBASE",
"HEXBASE",
"BINFRAC",
"OCTFRAC",
"HEXFRAC",
"EXPOMARK",
"EXPOSIGN",
"EXPONENT",
"ERROR"
};
#endif
// transition-table
static int fsm_table[16][11] = {
{PREFIX, DECBASE, DECBASE, DECBASE, HEXBASE, ERROR, HEXBASE, HEXBASE, ERROR,
DECPOINT, SIGN},
{PREFIX, DECBASE, DECBASE, DECBASE, HEXBASE, ERROR, HEXBASE,
HEXBASE, ERROR, DECPOINT, ERROR},
{OCTBASE, OCTBASE, OCTBASE, ERROR, ERROR, HEXBASE, BINBASE, ERROR, ERROR,
DECFRAC,
ERROR},
{DECFRAC, DECFRAC, DECFRAC, DECFRAC, HEXFRAC, ERROR, HEXFRAC, HEXFRAC,
EXPOMARK, ERROR, ERROR},
{DECFRAC, DECFRAC, DECFRAC, DECFRAC, ERROR, ERROR, ERROR, EXPOMARK, ERROR,
ERROR, ERROR},
{BINBASE, BINBASE, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK,
BINFRAC, ERROR},
{OCTBASE, OCTBASE, OCTBASE, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK,
OCTFRAC, ERROR},
{DECBASE, DECBASE, DECBASE, ERROR, ERROR, ERROR, ERROR, EXPOMARK, ERROR,
DECFRAC, ERROR},
{HEXBASE, HEXBASE, HEXBASE, HEXBASE, HEXBASE, ERROR, ERROR, ERROR, EXPOMARK,
HEXFRAC, ERROR},
{BINFRAC, BINFRAC, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK, ERROR,
ERROR},
{OCTFRAC, OCTFRAC, OCTFRAC, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK,
ERROR, ERROR},
{HEXFRAC, HEXFRAC, HEXFRAC, HEXFRAC, HEXFRAC, ERROR, HEXFRAC, HEXFRAC,
EXPOMARK, ERROR, ERROR},
{EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR,
ERROR, EXPOSIGN},
{EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR,
ERROR, ERROR},
{EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR,
ERROR, ERROR},
{ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR}
};
#include <ctype.h>
static int check_type(char c)
{
int type;
switch (tolower(c)) {
case '0':
type = ZERO;
break;
case '1':
type = BINDIG;
break;
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
type = OCTDIG;
break;
case '8':
case '9':
type = DECDIG;
break;
case 'a':
case 'c':
case 'd':
case 'f':
type = HEXDIG;
break;
case 'x':
type = PREHEX;
break;
case 'b':
type = PREBIN;
break;
case 'e':
type = EXPDEC;
break;
case 'p':
type = EXPBIN;
break;
case '.':
type = DECPNT;
break;
case '+':
case '-':
type = SGNCHR;
break;
default:
type = OTHER;
break;
};
return type;
}
// some variables to hold the relevant parts of a real number
static int main_sign = 1;
static int expo_sign = 1;
static double integral_part = 0.0;
static double fractional_part = 0.0;
static int hex_frac = 0;
static int dec_frac = 0;
static int oct_frac = 0;
static int bin_frac = 0;
static int exponent_part = 0;
// flags with both a boolean and a numerical value
// prob. not the best idea but simple
#define DECIMAL_EXP 10
#define BINARY_EXP 2
static int exponent_binordec = 0;
// assuming ASCII. Full map for more bases in the future.
// Far future.
static const char digit_map[] = {
-1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x07
-1, -1, -1, -1, -1, -1, -1, -1, // 0x08-0x0f
-1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x17
-1, -1, -1, -1, -1, -1, -1, -1, // 0x18-0x1f
-1, -1, -1, -1, -1, -1, -1, -1, // 0x20-0x27
-1, -1, 1, -1, -1, -1, -1, -1, // 0x28-0x2f '+' = 0x2b, '-' = 0x2d
0, 1, 2, 3, 4, 5, 6, 7, // 0x30-0x37
8, 9, -1, -1, -1, -1, -1, -1, // 0x38-0x3F
-1, 10, 11, 12, 13, 14, 15, -1, // 0x40-0x47
-1, -1, -1, -1, -1, -1, -1, -1, // 0x48-0x4f
-1, -1, -1, -1, -1, -1, -1, -1, // 0x50-0x57
-1, -1, -1, -1, -1, -1, -1, -1, // 0x58-0x5f
-1, 10, 11, 12, 13, 14, 15, -1, // 0x60-0x67
-1, -1, -1, -1, -1, -1, -1, -1, // 0x68-0x6f
-1, -1, -1, -1, -1, -1, -1, -1, // 0x70-0x77
-1, -1, -1, -1, -1, -1, -1, -1 // 0x78-0x7f
};
static int fsm(char input, int *state)
{
int res = FSM_OK;
input = tolower(input);
#ifdef DEBUG
printf("INPUT: %c [0x%2x] (%d) STATE: %-10s\n", input, input,digit_map[+input],st2str[*state]);
#endif
switch (*state) {
case START:
fprintf(stderr,
"Something is messed up in quite some hefty way and form!\n");
exit(EXIT_FAILURE);
case SIGN:
main_sign = digit_map[+input];
break;
case PREFIX:
// not used
break;
case DECPOINT:
// not used
break;
case DECBASE:
integral_part *= 10.0;
integral_part += digit_map[+input];
break;
case BINBASE:
integral_part *= 2.0;
integral_part += digit_map[+input];
break;
case OCTBASE:
integral_part *= 8.0;
integral_part += digit_map[+input];
break;
case HEXBASE:
if (input == 'x') {
break;
}
integral_part *= 16.0;
integral_part += digit_map[+input];
break;
case BINFRAC:
if (input == '.') {
break;
}
fractional_part *= 2.0;
fractional_part += digit_map[+input];
bin_frac++;
break;
case OCTFRAC:
if (input == '.') {
break;
}
fractional_part *= 8.0;
fractional_part += digit_map[+input];
oct_frac++;
break;
case DECFRAC:
if (input == '.') {
break;
}
fractional_part *= 10.0;
fractional_part += digit_map[+input];
dec_frac++;
break;
case HEXFRAC:
if (input == '.') {
break;
}
fractional_part *= 16.0;
fractional_part += digit_map[+input];
hex_frac++;
break;
case EXPOMARK:
exponent_binordec = (input == 'e') ? DECIMAL_EXP : BINARY_EXP;
break;
case EXPOSIGN:
expo_sign = digit_map[+input];
break;
case EXPONENT:
exponent_part *= 10;
exponent_part += digit_map[+input];
break;
case ERROR:
fprintf(stderr, "ERROR state reached\n");
exit(EXIT_FAILURE);
// "Run in circles, scream and shout!"
// Infantry Journal, Vol. 35, p. 396, United States Infantry Association, 1929
// Or was it Herman Wouk? The Caine Mutiny? No, that would be 1951 and too late.
break;
default:
fprintf(stderr, "Unexpected state with input %c\n", input);
*state = ERROR;
res = FSM_ERROR;
break;
}
return res;
}
static char *trim_both(char *s)
{
char *end,*p;
p = s;
while (isspace(*p)) {
p++;
}
if (*p == '\0') {
return p;
}
end = p + strlen(p) - 1;
while (end > p && isspace(*end)) {
end--;
}
*(end + 1) = '\0';
return p;
}
static int str2dbl(char *s, double *d)
{
int cur_state = START;
int type;
int res;
s = trim_both(s);
if(*s == '\0'){
// empty input, would an error be better?
*d = 0.0;
return FSM_OK;
}
if(*s == '0' && *(s+1) == '\0'){
*d = 0.0;
return FSM_OK;
}
if (!strncasecmp(s, "-inf", 4)) {
*d = -INFINITY;
return FSM_OK;
}
if (!strncasecmp(s, "+inf", 4) || !strncasecmp(s, "inf", 3)) {
*d = INFINITY;
return FSM_OK;
}
if (!strncasecmp(s, "-nan", 4) || !strncasecmp(s, "+nan", 4) || !strncasecmp(s, "nan", 3)) {
*d = NAN;
return FSM_OK;
}
while (*s != '\0') {
type = check_type(*s);
if (type == OTHER) {
fprintf(stderr, "OTHER: %c", *s);
return FSM_ERROR;
}
cur_state = fsm_table[cur_state][type];
res = fsm(*s, &cur_state);
if (res != FSM_OK) {
break;
}
s++;
}
printf("exp; %d, intp: %.20g, fracp: %.20g\n", exponent_part, integral_part,
fractional_part);
// The following will work with arbitray precision in production, use of
// a "double" is just for testing and not for real use. The error is
// larger than one ulp in way too many times
// the integral part needs no treatment, yet.
*d += integral_part;
// the fractional part needs to be shifted by the base to the right
if (hex_frac > 0) {
fractional_part /= pow(16, hex_frac);
} else if (dec_frac > 0) {
fractional_part /= pow(10, dec_frac);
} else if (oct_frac > 0) {
fractional_part /= pow(8, oct_frac);
} else if (bin_frac > 0) {
fractional_part /= pow(2, bin_frac);
}
printf("fracp: %.20g\n", fractional_part);
*d += fractional_part;
// (exponent_binordec != 0) also means that there is an exponent in the first place
if (exponent_binordec) {
if (expo_sign >= 0) {
*d *= pow(exponent_binordec, exponent_part);
} else {
*d /= pow(exponent_binordec, exponent_part);
}
}
*d *= main_sign;
return FSM_OK;
}
int main(int argc, char **argv)
{
int res;
char *input, *endptr;
double out, libc;
if (argc != 2) {
fprintf(stderr, "Usage: %s float\n", argv[0]);
exit(EXIT_FAILURE);
}
input = malloc(strlen(argv[1]) + 1);
if (input == NULL) {
fprintf(stderr, "Malloc failed to allocate a measly %zu bytes\n",
strlen(argv[1]) + 1);
exit(EXIT_FAILURE);
}
strcpy(input, argv[1]);
// all checks ommited!
libc = strtod(input, &endptr);
printf("\nINPUT: %s\t%g\t%s\n\n", input, libc, endptr);
out = 0.0;
res = str2dbl(input, &out);
printf
("fsm returned %d and the result (if any) is: \n\tinp: %s\n\town: %.20g\n\tlibc: %.20g\n",
res, trim_both(input) ,out, libc);
free(input);
exit(EXIT_SUCCESS);
}
아마도 'strtod'를 사용해야합니다. – keltar
@keltar 제안에 감사드립니다. – terribleProgrammer
@terribleProgrammer 게시물을 변경하는 것보다 답변을 답으로 게시하는 것이 좋습니다. 그것이 그대로,이 대답은 문제가 있습니다. – chux