`strtod(&Q;3EX&q;,&end)`应该是什么结果?‘sscanf’怎么样? [英] What is the result of `strtod("3ex", &end)` supposed to be? What about `sscanf`?

查看:18
本文介绍了`strtod(&Q;3EX&q;,&end)`应该是什么结果?‘sscanf’怎么样?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的实验中,此表达式

double d = strtod("3ex", &end);
3.0初始化d,并将end指针放在输入字符串中的'e'字符处。这正是我期望它的表现。'e'字符可能看起来是指数部分的开头,但由于缺少实际指数值(6.4.4.2所需),因此'e'应被视为完全独立的字符。

但是,当我这样做时

double d;
char c;
sscanf("3ex", "%lf%c", &d, &c);

我注意到sscanf使用'3''e'作为%lf格式说明符。变量d接收3.0值。变量c'x'结尾。这在我看来很奇怪,原因有两个。

首先,由于语言规范在描述%f格式说明符的行为时引用了strtod,因此我直观地期望%lf以与strtod相同的方式处理输入(即选择与终止点相同的位置)。但是,我知道在历史上scanf应该向输入流返回不超过一个字符。这将scanf可以执行的任何前瞻的距离限制为一个字符。并且上面的示例需要至少两个字符的前瞻。因此,假设我接受%lf同时使用输入流中的'3''e'这一事实。

然后我们遇到了第二个问题。现在sscanf必须将该"3e"转换为类型double"3e"不是浮点常量的有效表示形式(同样,根据6.4.4.2,指数值不是可选的)。我希望sscanf将此输入视为错误:在%lf转换期间终止,返回0,并保持dc不变。但是,上述sscanf已成功完成(返回2)。

这一行为在GCC和标准库的msvc实现中是一致的。

那么我的问题是,在C语言标准文档中,究竟在什么地方允许sscanf如上所述的行为,指的是上述两点:消费多于strtod行为,并且成功地将"3e"这样的序列转换为"3e"

通过查看我的实验结果,我可能可以对sscanf的行为进行"反向工程":尽可能"看起来正确"而不后退,然后只将使用的序列传递给strtod。这样,'e'%lf消费,然后被strtod忽略。但是语言规范中就只有这些吗?

推荐答案

我只是在die.net

上找到下面的描述
strtod()、strtof()和strtered()函数将初始 NPTR指向双精度、浮点型和长整型的字符串部分 分别为双重表示。

字符串(初始部分)的预期形式是可选的 isspace(3)识别的前导空格,可选加号 (‘+’)或减号(‘-’),然后(I)一个十进制数,或 (Ii)十六进制数;或(Iii)无穷大;或(Iv)NaN (不是数字)。

十进制数由非空的十进制数字序列组成 可能包含基数字符(小数点, 取决于区域设置,通常为"."),可选择后跟小数 指数。十进制指数由"E"或"e"组成,后跟 可选的加号或减号,后跟一个非空序列 十进制数字,表示乘以10的幂。

十六进制数由"0x"或"0x"后跟非空 可能包含基数字符的十六进制数字序列, 可选地后跟二进制指数。一个二进制指数由 表示"p"或"p",后跟一个可选的加号或减号 用非空的十进制数字序列表示乘法 2的幂。基数字符和二进制指数中的至少一个 必须存在。

无穷大可以是"INF"或"infinity",不区分大小写。

NaN可以选择"nan"(不区分大小写)后跟‘(’,a 字符序列,后跟‘)’。字符串 以依赖于实现的方式指定NaN的类型。

然后我做了一个实验,我和GCC一起执行了下面的代码

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

char head[1024], *tail;

void core(const char *stmt){
    sprintf(head, "%s", stmt);
    double d=strtod(head, &tail);
    printf("cover %s to %.2f with length=%ld.
", head, d, tail-head);
}

int main(){
    core("3.0x");
    core("3e");
    core("3ex");
    core("3e0x");

    return 0;
}

并获取结果

cover 3.0x to 3.00 with length=3.
cover 3e to 3.00 with length=1.
cover 3ex to 3.00 with length=1.
cover 3e0x to 3.00 with length=3.

因此,"e"后面似乎应该有一些数字。

对于sscanf,我用GCC代码做了另一个实验:

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

char head[1024];

void core(const char *stmt){
    int i;sscanf(stmt, "%x%s", &i, head);
    printf("sscanf %s catch %d with '%s'.
", stmt, i, head);
}

int main(){
    core("0");
    core("0x0g");
    core("0x1g");
    core("0xg");

    return 0;
}

然后获取以下输出:

sscanf 0 catch 0 with ''.
sscanf 0x0g catch 0 with 'g'.
sscanf 0x1g catch 1 with 'g'.
sscanf 0xg catch 0 with 'g'.

sscanf似乎会尝试捕获更多字符,如果它当前判断它是合法的(可能是非法的,情况不完整),它将不会回滚。

这篇关于`strtod(&Q;3EX&q;,&amp;end)`应该是什么结果?‘sscanf’怎么样?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆