哪里定义了前缀相关的整数解析?

Col*_*lin 9 c++ language-lawyer

我有一个简单的测试程序(错误检查已删除):

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

int main() {
    std::string line;
    while(std::cin >> line) {
        int value;
        std::stringstream stream(line);

        stream >> std::setbase(0) >> value;

        std::cout << "You typed: " << value << std::endl;
    }

}
Run Code Online (Sandbox Code Playgroud)

哪个适用于依赖于前缀的整数解析.它会解析字符串开头"0x""0X"十六进制和字符串开始'0'为八进制.我在使用和看过的几个资源中对此进行了解释.然而,我无法找到的是C++标准中的一个指示,即它可以保证有效.

C标准strtol中的第7.20.1.4.3节说(6.4.4.1是整数常量的语法)我想抽象运算符在引擎盖下使用它:

如果base的值为零,则主题序列的预期形式是如6.4.4.1中所述的整数常量的形式,可选地前面加上或减号,但不包括整数suf fi x.

这适用于我尝试过的几个GCC版本,但一般使用它是否安全?

zwo*_*wol 5

setbase 在C++ 98 [lib.std.manip]/5中定义,略有释义

smanip setbase(int base);
Run Code Online (Sandbox Code Playgroud)

返回:s未指定类型的对象,使得[ s从流中插入或提取的行为就像在该流上调用以下函数一样:]

ios_base& f(ios_base& str, int base)
{
    str.setf(n == 8 ? ios_base::oct :
             n == 10 ? ios_base::dec :
             n == 16 ? ios_base::hex :
             ios_base::fmtflags(0), ios_base::basefield);
    return str;
}
Run Code Online (Sandbox Code Playgroud)

好的,所以,如果base不是8,10或16,则basefield清除标志.清除输入的效果basefield在[lib.facet.num.get.virtuals],表55("整数转换")中定义为与sscanf("%i")下一个可用字符序列等效.

C++ 98引用C89的定义*scanf,自然就够了.我没有C89的PDF副本,但我确实有C99,其中第7.19.6.2节第12段[C标准没有C++标准所具有的好的符号部分名称]定义"%i"的行为strtol与基础参数0.

所以好消息是,依赖于前缀的整数扫描是由标准保证的setbase(0).在消息是,iostream的格式化输入中的定义的*scanf,这意味着在C99 7.19.6.2p10结束可怕的句子适用:

如果[接收扫描结果的对象]没有合适的类型,或者无法在对象中表示转换结果,则行为未定义.

(强调我的.)该句子更清晰:输入溢出触发未定义的行为.如果输入有太多数字,则允许C(++)运行时崩溃程序*scanf!这是(其中一个原因)为什么我和其他人一直说不*scanf应该使用,现在我必须开始说它istream >> int.:-(

对C语言的建议更容易在C++中应用:阅读整行std::getline并手动解析它们.使用strtol函数族将数字输入转换为机器编号.(这些函数在溢出时具有可预测的行为.)