C 检查意外用户输入的方法

C 检查意外用户输入的方法,c,validation,input,C,Validation,Input,我明白了,一个人永远不应该相信用户的输入。在处理它之前检查它已经成为一种习惯。我几乎总是使用这种类型的函数,并且经常想知道这两个版本之间是否有差异 下面是我的检查函数的简单示例: 第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 A

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

下面是我的检查函数的简单示例:

第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;
}

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

首先:您的返回值与您随后进行的检查不匹配。如果你认为结果是一个错误代码,0表示成功,那么你必须通过<代码>(如果.CasaScCII(C))< /C> >进行测试。如果你认为结果是布尔值,那么你需要反转返回的值。在这种情况下,我建议包括
,将返回类型更改为
bool
,并将函数重命名为
isASCII
。这将使你的意图更加明显

比较您的两个版本,我想说,总的来说,这两个版本都不优于另一个版本——这取决于您正在编程的环境

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

另一方面,如果您只编写程序中使用的帮助器函数,变体1可能更方便:

  • 您可以直接在发生故障的函数中提供更细粒度的输出,而无需在函数外计算一些errno或返回值(这可能是库函数提供有关出错原因的进一步信息的方式)
  • 当您调用测试函数时,能够依赖已经完成的日志记录是很方便的,特别是在频繁调用检查函数的情况下,这样您就可以继续编写代码了

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

比较您的两个版本,我想说,总的来说,这两个版本都不优于另一个版本——这取决于您正在编程的环境

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

另一方面,如果您只编写程序中使用的帮助器函数,变体1可能更方便:

  • 您可以直接在发生故障的函数中提供更细粒度的输出,而无需在函数外计算一些errno或返回值(这可能是库函数提供有关出错原因的进一步信息的方式)
  • 当您调用测试函数时,能够依赖已经完成的日志记录是很方便的,特别是在频繁调用检查函数的情况下,这样您就可以继续编写代码了

是,将所有
char
s更改为
int
s(所有这些函数都需要
int
getc
需要一个,以便捕获
EOF
,以及ctype系列函数。
if(!checkASCII(c))
?@BLUEPIXY只检查失败,因为检查失败和成功都是无用的?我的评论是,这与它的意图相反。关于可移植性的兴趣点:
isascii()
不在标准库中,而是gcc中的BSD扩展,并且在POSIX中。将
isascii()
标记为已过时,并声明此函数可能会从未来版本中删除。是的,将所有
char
s更改为
int
s(所有这些函数都需要
int
getc
需要一个,以便捕获
EOF
,以及ctype系列函数。
if(!checkASCII(c))
?@BLUEPIXY只检查失败,因为检查失败和成功都是无用的?我的评论是,这与它的意图相反。关于可移植性的兴趣点:
isascii()
不在标准库中,而是gcc中的BSD扩展,并且在POSIX中。将
isascii()
标记为已过时,并声明此函数可能会从将来的版本中删除。如果我必须编写库,为流添加参数以打印版本1中的错误会是一个好主意吗?或者设置一个全局常量变量,该变量将在每个检查函数中调用?@Badda通过添加一个流参数,您可以强制用户提供一个参数——即使他根本不想有任何日志记录/输出——或者流可能与他自己的日志记录系统不兼容,因此他必须以任何合适的方式解决此问题(比如创建自己的流实现,这可能效率低下)。全局变量-好吧,它不能是常量,否则您不能设置它…但正是出于这个目的,已经有一个:
errno
(include
errno.h
)。优点:(通常!)它是线程安全的,因为每个线程都有一个实例……顺便说一下,BADA——流是C++概念,用C来获得这样的灵活性比较困难。