输入时为什么忽略前导零?

时间:2018-03-22 05:54:38

标签: c++ language-lawyer

当您撰写21600并输入int i; cin >> i;00325时,两个输入的行为都与325相同。但为什么?我认为当您输入i = 325;i的值设置为0,而下一个00325产生cin >>i;并且下一个i = 0;产生了cin >> i;。我知道i = 325;可以是八进制数,但我现在输入数字作为十进制数字(我没有使用00325操纵器)。

哪些书面证据可以保证这种行为?我快速浏览了N4140,却找不到任何证据。

注意:我想要的是不知道在输出时保留前面的零的方法,这在How can I pad an int with leading zeros when using cout << operator?中讨论。

只要有人给我一个像

这样的句子,我的问题就会得到解决

oct

在一些可靠的文件中。

2 个答案:

答案 0 :(得分:5)

警告: 提前非常无聊的答案

C ++ 14 [istream.formatting.arithmetic]¶3

operator>>(int& val);
     

转换发生时好像由以下代码片段执行(使用与for相同的表示法)   前面的代码片段):

typedef num_get<charT,istreambuf_iterator<charT,traits> > numget;
iostate err = ios_base::goodbit;
long lval;
use_facet<numget>(loc).get(*this, 0, *this, err, lval);
if (lval < numeric_limits<int>::min()) {
    err |= ios_base::failbit;
    val = numeric_limits<int>::min();
} else if (numeric_limits<int>::max() < lval) {
    err |= ios_base::failbit;
    val = numeric_limits<int>::max();
} else
    val = static_cast<int>(lval);
setstate(err);

这里的咕噜声工作由num_get::get完成,在{em> [facet.num.get.members]¶1指定:

iter_type get(iter_type in, iter_type end, ios_base& str,
     ios_base::iostate& err, long& val) const;
     

[...]   返回do_get(in, end, str, err, val)

之后立即定义

do_get [facet.num.get.virtuals] ),其中详细说明了整个shebang的确切工作方式。我不会复制三页的痛苦,而只是重点。

在阶段1中,根据流标志确定“等效stdio格式说明符”,如表85和86所示; std::ios_base的默认值为dec | skipws,因此我们将遵循该路径(对应于%d)。此外,还为下一阶段确定了一些其他区域设置和特定于标志的字符。

在阶段2中,从流中读取字符并将其累积在缓冲区中;你的问题的关键点是

  

如果没有丢弃,则进行检查以确定是否允许c作为阶段1返回的转换说明符的输入字段的下一个字符。如果是,则累计

因此,决定继续阅读你的零或在一个零之后停止取决于上面的%d;我们会回到它。

在第3阶段,累积的字符最终转换为long

  

通过标题<cstdlib>中声明的其中一个函数的规则:

     
      
  • 对于有符号整数值,函数strtoll
  •   

%d说明符和strtoll都在C标准中定义(C ++ 14指的是C99);让我们把它们挖出来。

C99§7.19.6.2¶12(谈论fscanf时),它被告知

  

d匹配一个可选的带符号十进制整数,其格式与strtol函数的主题序列的预期相同,base参数的值为10.

所以归结为strtol / strtoll,我们可以在C99§7.20.1.4找到。指定跳过最长的空白序列,然后考虑“主题序列”:

  

如果base的值为零,则主题序列的预期形式是6.4.4.1中描述的整数常量的形式,可选地前面带有加号或减号,但不包括整数后缀。如果base的值介于2和36之间(包括),则主题序列的预期形式是字母和数字序列,表示由base指定的基数的整数,可选地前面带有加号或减号,但不包括整数后缀。来自a(或A)到z(或Z)的字母归因于值10到35;只允许其归属值小于基数的字母和数字。如果base的值为16,则字符0x0X可以选择在字母和数字序列之前,如果存在,则在符号后面。

     

主题序列被定义为输入字符串的最长初始子序列,从第一个非空白字符开始,即预期形式。如果输入字符串为空或完全由空格组成,或者第一个非空白字符不是符号或允许的字母或数字,则主题序列不包含任何字符。

     

如果主题序列具有预期形式且base的值为零,则根据6.4.4.1的规则将以第一个数字开头的字符序列解释为整数常量。如果主题序列具有预期形式并且base的值在2和36之间,则将其用作转换的基础,将其值归于每个字母,如上所述。如果主题序列以减号开头,则转换产生的值将被否定(在返回类型中)。

(ibidem,¶3-5)

正如您所看到的,对于前导零没有特殊规定;如果它是一个有效的数字,它将进入主题序列,并在同一批次中进行处理。

答案 1 :(得分:1)

不会忽略前导零;它们在处理时被考虑,但保存在变量中的结果值与其他一些文本输入相同。

相同的“数学”数字可以有多个文本表示,有时取决于区域设置。对于阿拉伯数字,0325等于+325且等于325。根据所选的区域设置,以下文本可能具有相同的数值:

  • 123,456.89
  • 123.456,89
  • 123456.89
  • 123 456,89(记住半空间符号为千位分隔符)

让我们不要忘记其他数字书写系统,如罗马或Herbew,中文等。

多个数字表示的问题甚至比简单的人类传统更深,并且发生在编程之外的纯数学中。可以证明,像12.9(9) [12.9999999 ...]这样的理性无穷分数在所有方面都与13相等。

  

我认为如果我的值设置为0则更自然

这将假设符号“0”在输入解析中与[1-9]区别对待。但为什么呢?