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

C++ 哪里定义了前缀相关的整数解析?,c++,language-lawyer,C++,Language Lawyer,我有一个简单的测试程序(删除错误检查): #包括 #包括 #包括 #包括 int main(){ std::字符串行; 而(标准::cin>>行){ int值; std::stringstream(行); 流>>std::setbase(0)>>值; 标准::cout§22.4.2.1.2/3,表85: 对于转换为整数类型,该函数确定积分转换说明符,如表85所示。该表是有序的。即,条件为true的第一行适用 %i转换格式用于scanf和company进行前缀相关转换。setbase在C++98[

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

#包括
#包括
#包括
#包括
int main(){
std::字符串行;
而(标准::cin>>行){
int值;
std::stringstream(行);
流>>std::setbase(0)>>值;

标准::cout§22.4.2.1.2/3,表85:

对于转换为整数类型,该函数确定积分转换说明符,如表85所示。该表是有序的。即,条件为true的第一行适用


%i
转换格式用于
scanf
和company进行前缀相关转换。

setbase
在C++98[lib.std.manip]/5中定义,稍作解释

smanip setbase(int base);
返回:未指定类型的对象
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;
}
好的,那么,如果
base
不是8、10或16,那么
basefield
标志将被清除。清除的
basefield
对输入的影响在[lib.facet.num.get.virtuals]表55(“整数转换”)中定义为相当于
sscanf(“%i”)
对下一个可用字符序列的影响

C++ 98是指C89定义的代码> *SCAFF < /C>,自然地,我没有C89的PDF拷贝,但是我有C99,其中7.19.62段落12(C标准没有C++标准所定义的漂亮的符号节名)定义了< > > %i

与基本参数为0的strtol的行为相同

因此,好消息是,
setbase(0)
之后的标准保证了前缀相关整数扫描。坏消息是,iostream格式的输入定义为
*scanf
,这意味着C99 7.19.6.2p10结尾的可怕句子适用:

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

(我的重点)这句话的更清晰版本:输入溢出触发未定义的行为。如果输入到
*scanf
的数字太多,则允许C(++)运行时使程序崩溃!这是(几个原因之一)为什么我和其他人一直说永远不应该使用
*scanf
,现在我不得不开始说
istream>>int
:-(


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

让我们从§27.6.3“标准操纵器”开始,5,“
smanip收进基(int-base)
”:

返回:未指定类型的对象
s
,如果
中的
基本流的(实例)
,则 >>s
中的表达式
的行为就像调用了
f(s)
一样。其中
f
可以定义为:

ios_base& f(ios_base& str, int base)
{
  // set basefield
  str.setf(base == 8 ? ios_base::oct :
    base == 10 ? ios_base::dec :
    base == 16 ? ios_base::hex :
    ios_base::fmtflags(0), ios_base::basefield);
  return str;
}
我们通过§27.4.2.2
ios_-base-fmtflags
状态函数,^6
fmtflags-setf(fmtflags-fmtfl,fmtflags-mask);

效果:在
flags()
中清除
mask
,在
flags()
中设置
fmtfl和mask

那么,在
flags()
中设置
0&basefield
有什么效果呢

考虑§27.6.1.2.2算术提取器,其中描述了
运算符>>(int&val);

这些提取器依赖于区域设置的num_get(22.2.2.1)对象 执行输入流数据的解析

§22.2.2.1,^4,表55描述了在这种情况下选择的转换说明符:

basefield == 0, `%i`
最后,^11说:

一系列字符…被转换(根据
scanf
)转换为val类型的值


<> P> >,C++标准,2003,表示<代码> STD::CIN > SETBASE(0)> I/COM>相当于<代码> SCANF(…,“%i”,和i)< /C> > /P>
对于意味着什么,你需要参考C标准。

很好的发现。我想这必须有一些C标准的链接,但始终无法找到它。嗯,第三个要在五分钟前完成。无论如何,我会把它留在这里,以防引用任何人。
ios_base& f(ios_base& str, int base)
{
  // set basefield
  str.setf(base == 8 ? ios_base::oct :
    base == 10 ? ios_base::dec :
    base == 16 ? ios_base::hex :
    ios_base::fmtflags(0), ios_base::basefield);
  return str;
}
basefield == 0, `%i`