【问题标题】:gets_s() expected behaviorgets_s() 预期行为
【发布时间】:2020-11-23 12:52:16
【问题描述】:

tl;dr

如果下一个换行符是stdin 中的nth 字符,是否违反约束?


实施gets_s(),我想知道我认为标准措辞中的矛盾之处。

标准的定义(附件 K)如下(强调我的):

char *gets_s(char *s, rsize_t n);

运行时约束

[...] 换行符、文件结尾或读取错误应在读取中发生 n-1 个字符来自stdin

[...]

gets_s 函数读取的字符数最多比n 指定的字符数少一个 从stdin指向的流,进入s指向的数组。无需额外 在换行符(被丢弃)或文件结尾之后读取字符。 丢弃的换行符不计入读取的字符数。

让我们假设换行符作为输入的nth 字符出现。最明显的例子是n == 1stdin 流中的下一个字符是换行符。

我应该...

  • ...认为这是违反约束(n - 1 == 0 中没有换行符从stdin 读取的字符)?这意味着调用约束违规处理程序,并返回NULL

  • ...读取换行符,丢弃它(不计入读取的字符数),然后返回s?

任何一种情况都会看到s[0] = '\0',并且(包括在内)从stdin 读取/丢弃的换行符。

【问题讨论】:

  • @AdrianMole:由于标准的其余部分处理透明缓冲的问题,并且流的缓冲可能是 _IOFBF 以及 _IOLBF_IONBF,我看不出有理由假设这个函数的定义突然玩起了“读取”和“处理”的游戏。
  • @AdrianMole:嗯,我的第一个引用块的第一句话与我的第二个引用块的最后一句话相矛盾。 这是手头的问题。 除非您觉得我的问题有什么不清楚的地方,否则请随意尝试实际的答案...(无意冒犯,我只是觉得您的印象是在此处的评论中暗示答案。)
  • @AdrianMole 但是new-line character does not count towards number of characters read.gets_sabc 之后读取<newline> 时,读取的字符数保持在3,因为换行符不计算在内。这正是问题所在。因为对于char b[4]; gets(b) 提供abc\n 作为输入很好。
  • 标准引用的第一部分指出前 n-1 (!!) 个字符中没有换行符是违反约束(调用失败)。这就是矛盾。我完全同意您的 interpretation 是有道理的(n 是缓冲区大小,因此会有 n-1 个字符的空间加上一个零终止符)。所以我们在标准的措辞中有一个“错误”?这是一个答案,而不是试图澄清问题的评论。
  • 变量 n 是否在gets_s 函数的范围内发生变化是一个不相关的实现细节。 我的 实现倒计时,因为除非必要,否则我不相信生成本地循环计数器,并且我不需要函数末尾的 n 的原始值(而不是s 的原始值)。

标签: c language-lawyer


【解决方案1】:

我的理由是gets_sgets 的安全版本。当char b[4]; gets(b) 然后阅读abc\nabc<eof> 很好,那么我认为gets_s(b, 4) 也应该很好。来自K.1p5The alternative functions verify that output buffers are large enough for the intended result and return a failure indicator if they are not.

我相信你的推理是正确的。因为discarded new-line character does not count towards number of characters read 它不计入“从标准输入读取 n-1 个字符”。但是我认为措辞是错误的。

microsoft documentation gets_s 的措辞有点不同:

[...] 如果缓冲区太小而无法包含输入行 [...] 这些函数调用无效的参数处理程序


认为这是违反约束(从标准输入读取的 n - 1 == 0 个字符内没有换行符)?

没有。

读取换行符,丢弃它(不计入读取的字符数),然后返回 s?

是的。

【讨论】:

  • 另一个花絮:即使n'th 读取的字符不是换行符,您也不必“ungetc”它,因为处理违反约束要求您继续阅读(不写入s),直到您确实遇到换行符。这种认识让我更清楚了。
【解决方案2】:

我们先试着分析一下第二句,特别是:

丢弃的换行符不计入 读取的字符。

这意味着,在我对英语的(相当流利的)理解中,对于给定的n 值(缓冲区大小)4 和输入abc\n,那么,当遇到换行符时'(或 已解析已处理 - 您喜欢的任何特定动词),已读取的字符数为 3(即 n-1)。

因此,回到第一句话:

...应在读取 n-1 个字符内发生

我们可以(明确地)说在阅读n-1 个字符时出现了换行符(该动词的另一个选项)。

这同样适用于您的 n == 1 案例:当读取 0 字符时会出现换行符。

【讨论】:

    【解决方案3】:

    如果下一个换行符是 stdin 中的第 n 个字符,是否违反约束?

    在我看来:没有。


    OP 很好地列出了可能存在冲突/不清楚的规范。

    但回到 gets_s() 的作用,替换 gets()

    在输入"123\n" 的情况下,以下两个函数都应该可以正常工作,没有未定义的行为 (UB) 也没有违反约束。

    char s[4];
    gets(s);
    gets_s(s, sizeof s);
    

    IOW,如果输入不会导致 gets() 出现 UB,则相同的输入不应导致 gets_s() 违反约束。

    如果规范在这一点上不清楚/不同,它应该改变。

    OTOH, gets_s() 附件 K 可能无法在下一个版本中保留。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-09
      • 1970-01-01
      • 2017-04-22
      • 2019-01-06
      相关资源
      最近更新 更多