6

规范在strtol概念上将输入字符串分为“初始空白”、“主题序列”和“最终字符串”,并将“主题序列”定义为:

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

有一次我认为“最长的初始子序列”业务类似于工作方式scanf,其中"0x@"将扫描为"0x",一个失败的匹配,然后"@"是下一个未读字符。但是,经过一些讨论,我主要相信strtol处理的是预期形式的最长初始子序列,而不是最长的初始字符串,它是预期形式的某些可能字符串的初始子序列。

仍然让我感到困惑的是规范中的这种语言:

如果主题序列为空或没有预期的形式,则不进行转换;str 的值存储在 endptr 指向的对象中,前提是 endptr 不是空指针。

如果我们接受似乎是“主题序列”的正确定义,则不存在没有预期形式的非空主题序列之类的东西,相反(为了避免冗余和混淆)文本应该只是阅读:

如果主题序列为空,则不进行转换;str 的值存储在 endptr 指向的对象中,前提是 endptr 不是空指针。

谁能为我澄清这些问题?也许指向过去讨论或任何相关缺陷报告的链接会很有用。

4

4 回答 4

3

我觉得C99语言说的很清楚:

主题序列被定义为输入字符串的最长初始子序列,从第一个非空白字符开始,即具有预期形式。

给定"0x@","0x@"不是预期的形式;"0x"不是预期的形式;因此"0"是具有预期形式的最长初始子序列。

我同意这意味着您不能拥有不符合预期形式的非空主题序列 - 除非您解释以下内容:

在地区以外的其他"C"地区,可以接受额外的地区特定主题序列形式。

...因为允许语言环境定义主题序列可能具有的其他可能形式,但这些形式仍然不是“预期形式”。

最后一段中的措辞似乎只是“腰带和大括号”。

于 2011-07-15T01:37:10.583 回答
2

如果您从 C9​​9 标准的 §7.20.1.4(strtol、strtoll、strtoul 和 strtoull 函数)¶2 而不是 ¶4 开始,可能会更容易理解:

¶2 strtol、strtoll、strtoul 和 strtoull 函数将 nptr 指向的字符串的初始部分分别转换为 long int、long long int、unsigned long int 和 unsigned long long int 表示形式。首先,他们将输入字符串分解为三部分:一个初始的,可能为空的空白字符序列(由 isspace 函数指定),一个类似于整数的主题序列,该整数表示为由 base 的值确定的某个基数,以及一个或多个无法识别的字符的最终字符串,包括输入字符串的终止空字符。然后,他们尝试将主题序列转换为整数,并返回结果。

¶3 如果 base 的值为零,则主题序列的预期形式是 6.4.4.1 中描述的整数常量,前面可选加号或减号,但不包括整数后缀。如果 base 的值介于 2 和 36(含)之间,则主题序列的预期形式是表示整数的字母和数字序列,其基数由 base 指定,前面可选加号或减号,但不包括一个整数后缀。从 a(或 A)到 z(或 Z)的字母被赋予值 10 到 35;只允许赋值小于 base 的字母和数字。如果 base 的值为 16,则字符 0x 或 0X 可以可选地位于字母和数字序列之前,如果存在则在符号之后。

¶4主题序列被定义为输入字符串的最长初始子序列,...

特别是,¶3 阐明了主题序列是什么。

于 2011-07-15T05:08:35.027 回答
1

我完全同意您的评估:根据定义,所有非空主题序列都是预期的形式,因此标准的措辞是可疑的。

在浮点转换函数的情况下,还有另一个错误(C99:TC3 第 7.20.1.3 节,§3):

[...]主题序列被定义为输入字符串的最长初始子序列,从第一个非空白字符开始,即预期形式。如果输入字符串不是预期的形式,则主题序列不包含字符。

这意味着整个输入字符串必须是预期的形式,违背了endptr参数的目的。有人可能会争辩说,输入字符串的预期形式与主题序列的预期形式不同,但它仍然很混乱。

您也正确地认为函数strto*()*scanf()函数系列的语义是不同的:如果两者都匹配,它们将始终在值上达成一致并使用相同数量的字符(并且它们没有被破坏的任何 libc 实现,包括 newlib 和 glibc上次我检查),但也*scanf()无法匹配需要回溯多个字符的情况,如您的示例"0x@""1.0e+".

于 2011-07-15T08:18:58.847 回答
1

strtol的POSIX 规范似乎更清楚:

这些函数应将 str 指向的字符串的初始部分分别转换为 long 类型和 long long 表示。首先,他们将输入字符串分解为三部分:

  1. 一个初始的,可能为空的空白字符序列(由 isspace() 指定)

  2. 一个主题序列被解释为一个整数,表示为由 base 的值确定的一些基数

  3. 一个或多个无法识别的字符的最终字符串,包括输入字符串的终止 NUL 字符。

然后他们将尝试将主题序列转换为整数,并返回结果。

但当然,它不是规范性的,并且“遵循 ISO C 标准”。

于 2011-07-14T23:24:39.540 回答