【问题标题】:strcasecmp() : A Non-Standard Function?strcasecmp() :非标准函数?
【发布时间】:2015-06-29 23:34:41
【问题描述】:

前几天我在 CodeReview 上创建了一个帖子。一位回答我的问题的人建议我不要使用 strcasecmp(),因为“函数是非标准的 [并且] 这使得 [我的] 代码不可移植”。我是这样使用的:

int playGame()
{

    char scanned[3];
    printf("Do you wish to play tick-tack-toe?\n");
    scanf("%s", scanned);
    if(strcasecmp(scanned,"yes")==0)
        startGame();

    else
    {
        if (strcasecmp(scanned,"no")==0 || strcasecmp(scanned,"nah")==0 || strcasecmp(scanned,"naw")==0)
        {
            printf("That's too bad!/nThis program will now end.");
            return 1;
        }
        printf("Not valid input!/nThis program will now end.");
        return 1;
    }
return 0;
}

有人可以更深入地解释一下为什么 strcasecmp() 有这些限制吗?

【问题讨论】:

  • 为什么不直接检查standard
  • 但是哪个标准是“THE”标准?标准的伟大之处在于有这么多! strcasecmp 函数实际上是在 BSD/POSIX 的 libc 标准库中定义的。
  • 就我个人而言,我只会检查第一个字符是“N”还是“n”并收工,而不是试图解释特定的俚语实例。但在这里,我们遇到了一个更大的问题,即计算机试图解析人工生成的文本输入。
  • @Dan-korn,你不是很懂行吗:P
  • 如有疑问 man 3 strcasecmp :“符合 4.4BSD,POSIX.1-2001。”

标签: c string comparison


【解决方案1】:

strcasecmp 不在 C 或 C++ 标准中。它由 POSIX.1-2001 和 4.4BSD 定义。

如果您的系统符合 POSIX 或 BSD,则不会有任何问题。否则,该功能将不可用。

【讨论】:

  • 这完全是误解。仔细阅读:“以 str 开头后跟小写字母的名称由 C 标准保留”。这意味着如果 you 编写了一个名为 strcasewhatever 的函数,那么 you 就刚刚离开了 C 标准。 strcmp 是 C 标准的一部分
  • @SuperGoA:我是认真的。 C 标准将strcmp() 定义为其函数之一,并且还保留了以str 和小写字母开头的其他名称。 POSIX 使用strcasecmp() 踏上该保留的名称空间,但侥幸逃脱。如果你创建了一个函数strcasecmp(),你不一定能成功,但strCaseCmp()str_casecmp()str9cmp() 是可以的(str 后面没有小写字母三)。当然,如果系统没有达到应有的纪律性,您仍然可能会遇到问题。
  • 请注意,strcasecmp() 是在 1997 年由 Single Unix Specification v2 定义的。我不确定它当时是否在 POSIX 中,但strcasecmp() 的历史比2001 年参考。
  • 与其说是平台,不如说是关于 C 编译器及其库。您可以像在 Unix 或 OS X 上一样在 Windows 上安装 MinGW 并调用 strcasecmp,即使您使用 Visual Studio 时它也不起作用。或者,您也可以只 #define strcasecmp stricmp,或者根据工具集的需要,反之亦然。
  • 可能需要担心的是,函数的运行时实现如何确定哪些大写和小写字符在其不区分大小写的比较中是等效的?您可能会发现对于英语字符串来说一切正常,但是如果您给它提供带有其他语言(例如德语、法语、西班牙语)的重音或变音符号的字符串,那么它是否有效可能取决于实现,或者取决于“C”语言环境。然后是日语和汉语等宽字符语言;那完全是另一回事了。欢迎来到巴别塔!
【解决方案2】:

简短回答:由于strcasecmp() 不在 C 标准库中,因此它是非标准的。

strcasecmp() 是在 4.4BSD、POSIX.1-2001 等流行标准中定义的。

无大小写函数的定义为挑剔的细节打开了大门。这些通常涉及无案例比较的正面或负面结果,而不仅仅是 OP 使用的 0 或非 0。特别是:

在 POSIX 语言环境中,strcasecmp() 和 strncasecmp() 的行为就像字符串已转换为小写,然后执行字节比较一样。结果在其他语言环境中未指定。

问题在于大小写字母没有一对一的映射。考虑一个本地有 Eeé 但没有 Étoupper('é') -- > 'E' 。然后用“好像字符串被转换成小写一样”,'E' 有两个选择。

作为candidate 便携式解决方案,请考虑一种将字母往返(先到上然后再到下)以应对非一对一映射的解决方案:

int SGA_stricmp(const char *a, const char *b) {
  int ca, cb;
  do {
     ca = * (unsigned char *)a;
     cb = * (unsigned char *)b;
     ca = tolower(toupper(ca));
     cb = tolower(toupper(cb));
     a++;
     b++;
   } while (ca == cb && ca != '\0');
   return ca - cb;
}

如果您不想往返使用这些值:

     ca = tolower(ca);
     cb = tolower(cb);

详细信息:toupper()tolower() 仅在 unsigned charEOF 范围内为 int 定义。 * (unsigned char *)a 用作 *a 可能有负值。

【讨论】:

    【解决方案3】:

    “函数是非标准的”是指函数声明和契约没有在 C 国际标准中指定。

    “这使得代码不可移植”意味着,实现不需要实现strcasecmp(),因此您的代码不完全符合标准,并且不能保证由严格符合标准的编译器编译。

    strcasecmp() 本身就是 POSIX.1-20014.4BSD 规范 (link) 的一部分。

    【讨论】:

    • 我很抱歉,但我不明白这一点:“这使得代码不可移植意味着,实现不需要实现 strcasecmp()...”为什么不会实现如果 strcasecomp() 是非标准的,则需要。根据第一个答案,听起来需要一些“特殊”(POSIX.1-2001 或 4.4BSD)才能正常工作。
    • 他的意思是,如果函数不是 C 标准的一部分,则不需要符合标准的 C 编译器来实现它。因此,您的代码可能无法在世界上每个“标准”C 编译器上编译。
    • @SuperGoA 国际 C 标准作为一个单独的文档提供,从字面上描述了符合标准的 C 编译器必须/不得/不能/不能/不应该/不应该做的一切。严格遵守的 C 编译器将仅实现标准中的内容。 POSIX 不是标准的一部分,而是被广泛接受的扩展(规范)。在大多数 Windows 上,它根本没有实现。
    【解决方案4】:

    另一种方法是使用标准的 tolower() 将输入规范化为小写。然后你可以使用标准的 strcmp()。

    【讨论】:

    • 请注意,当大写/小写字母没有一对一映射时,这在功能上可能与 strcasecmp() 不同。它取决于strcasecmp() 规范(它不是 C 标准)。大多数strcasecmp() 确实使用这种tolower() 方法作为默认语言环境。
    猜你喜欢
    • 2017-03-19
    • 2015-04-18
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多