【问题标题】:Ways of checking an unexpected user input检查意外用户输入的方法
【发布时间】:2017-05-18 13:47:31
【问题描述】:

我了解到永远不应该相信用户的输入。在处理之前检查它已成为一种习惯。我几乎总是使用这种类型的函数,并且经常想知道这两个版本之间是否存在差异

这是我的检查功能的一个简单示例:

版本 1

int checkASCII(char c) // Here we check, print error and return if it succeeded or not
{
    if (!isascii(c))
    {
        fprintf(stderr, "Error. Not an ASCII character.\n.");
        return 1;
    }
    if (!isdigit(c))
    {
        fprintf(stderr, "Error. Not a number.\n.");
        return 1;
    }
    // potentially more checks
    return 0;
}

int printASCIINumber() // So that here we just have to verify the success
{
   char c;
   c = getc(stdin);
   if (checkASCII(c))
      putc(c, stdout);
   else return 1;
   return 0;
}

第 2 版

int checkASCII(char c) // Here we just check errors regardless of what failed
{
    if (!isascii(c))
      return 1;
    if (!isdigit(c)
      return 1;
    ... // potentially more checks
    return 0;
}

int printASCIINumber() // And here we verify success and print a general error message
{
   char c;
   c = getc(stdin);
   if (checkASCII(c))
      putc(c, stdout);
   else 
   {
      fprintf(stderr, "Error. Please input an ASCII number.\n");
      return 1;
   }
   return 0;
}

如果有任何目标需要改进,我也不反对。谢谢。

【问题讨论】:

  • 是的,将所有chars 更改为ints(所有这些函数都需要intgetc 想要一个以捕获EOF,并且ctype 系列函数也一样.
  • if (!checkASCII(c)) ?
  • @BLUEPIXY 只检查失败,因为检查失败和成功都没用?
  • 我的评论是它与它的意图相反。
  • 关于可移植性的兴趣点:isascii() 不在标准库中,而是在 gcc 中的 BSD 扩展,并且在 POSIX 中。 The POSIX Standardisascii() 标记为已过时,并声明此功能可能会从未来版本中删除。

标签: c validation input


【解决方案1】:

一开始:您的返回值与您之后所做的检查不匹配。如果您认为结果是错误代码,0 表示成功,那么您必须通过 if(!checkASCII(c)) 进行测试 - 如果您认为结果是布尔值,那么您需要反转返回的值。在这种情况下,我建议包括<stdbool.h>,将返回类型更改为bool,并将函数重命名为isASCII。这会让你的意图更加明显。

比较你的两个版本,我想说两者都没有比另一个更好 - 这取决于你正在编程的环境。

假设您正在编写一些通用库。那么我当然更喜欢变体 2,因为您不知道使用您的库的人是否需要控制台输出 - 或者控制台是否可用(Linux 守护进程、Windows 服务等)。无论出于何种原因,用户都可能希望使用自己的日志记录工具...

另一方面,如果您编写一些仅在程序中使用的辅助函数,则变体 1 会更方便:

  • 您可以直接在发生故障的函数中直接提供更细粒度的输出 - 无需在函数外部评估某些 errno 或返回值(这可能是库函数提供有关问题的进一步信息的方式) .
  • 这很方便,尤其是在频繁调用检查函数时,能够依赖于调用测试函数时已经完成的日志记录,因此您可以继续编写代码。

【讨论】:

  • 如果我必须编写一个库,在 Version 1 中添加一个用于打印错误的流参数是个好主意吗?或者设置一个全局 const 变量,它会在每个检查函数中调用?
  • @Badda 通过添加流参数,您强制用户提供一个 - 即使他根本不想有任何日志记录/输出 - 或者流可能与他自己的日志记录不兼容系统,所以他必须以任何合适的方式解决这个问题(比如创建自己的流实现,这可能效率低下)。全局变量 - 嗯,它不能是 const,否则你不能设置它……但正是出于这个目的,is 已经有一个:errno(包括errno.h)。优点:(通常!)它是线程安全的,因为每个线程有一个实例......
  • @Badda 顺便说一句 - 流是一个 C++ 概念,使用 C 获得这种灵活性有点困难。您很可能必须使用一个或多个函数指针,以便用户可以提供他自己的日志记录。例如。为了能够直接传入 printf,它可能看起来像这样:void test(int n, int (*loggingCallback)(char const*, ...))。但我坚持 - 我宁愿不这样做。还有一个论点:如果用户想要将输出国际化(例如,对于德语或西班牙语用户)怎么办?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-23
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2023-01-30
  • 2013-11-09
相关资源
最近更新 更多