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.2ios_-base-fmtflags
状态函数,^6fmtflags-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`