【问题标题】:C99 remove stricmp() and strnicmp()?C99 删除 stricmp() 和 strnicmp()?
【发布时间】:2015-08-24 08:58:36
【问题描述】:

函数 stricmp()strnicmp() 在 C99 中被删除了吗? 当我尝试针对 C99 编译它时,我总是收到警告 implicit declaration of function stricmp() (以及 strnicmp() )。 例如,下面的简单代码让我收到警告。

#include<string.h>
#include<stdio.h>

char arr[100]="hello";
char arr2[100]="hEllo";

int main()
{
   int n=-1;
   printf("%d\n",n);
   n=strnicmp(arr,arr2,3);   // the same when use the function stricmp();
   printf("%d\n",n);

   getchar();
   return 0;
}

当我尝试针对 C99(gcc -Wall -std=c99 main.c -o main) 编译这段代码时,我收到了警告。但是当我在没有-std=c99 的情况下编译它时,不会抛出任何警告。 但是,即使有隐式声明的警告,我的代码仍然可以正常工作。

这是为什么呢?那是一个错误吗?如果不是错误,那么导致该警告发生的 C99 的更改究竟是什么?

【问题讨论】:

标签: c string c99


【解决方案1】:

当代码用 C99 编译时,它符合 C99 标准,没有stricmp()。当代码在没有 C99 开关的情况下编译时,它符合实现stricmp() 的未知标准。 (假设 gcc 没有 -std=c99,可能编译为允许隐式声明的 C89/90 标准。)

正如@Joachim Pileborg 所评论的,不敏感的比较不是 C 标准的一部分。

对于 C99 隐式函数需要诊断(在这种情况下是警告)。如果没有 C99,函数的隐式使用不会产生警告。函数存在于 this 编译器的库中 - 只是函数在使用前声明的问题。

自己制作很容易:

int wal_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));
   } while (ca == cb && ca != '\0');
   return ca - cb;
}

注意:在编码和尝试使A-Z 匹配a-z 时,字符串不敏感的比较例程往往工作得很好。但是当试图order 字符串时,事情很快就会失控。 “abc”与“_bc”可以在另一个之前或之后,这取决于同情是大写还是小写。 '_',在 ASCII 中,存在于大小写字母之间。随着国际化和地区问题,情况变得更加复杂。我的代码示例使用往返转换来处理大写 char 的数量与小写字母不存在一对一映射的问题。 IMO 鲁棒不区分大小写比较的复杂性要求使用 UTF 编码及其大小写定义。


[编辑 2020]

为了应对那些废弃的非 2 补码以及 2 补码平台,需要进行代码更正。早期的代码会将 +0 和 -0 折叠成 unsigned 0。只有 +0 应该转换为 0。正确读取数据为 unsigned char 而不是 signed char 并转换。

注意:非 2 补码中的正确句柄现在大多是学术性的。

// ca = (unsigned char) *a++;
ca = *((unsigned char *) a++);
// also cb

【讨论】:

  • 为了获得轻微的性能提升:ca = *a; a++; if(islower(ca)) {ca = toupper(ca); } 等等。为您节省一些额外的检查。
  • 很抱歉,我无法完全理解您为什么在函数中使用“toupper()”和“tolower()”,尽管它工作得很好
  • @walkerlala toupper() 是一个标准的 C 函数,可将 int 转换为其等效的大写字母。 'a' --> 'A', 'A' --> 'A', '0' --> '0' 等。它对所有unsigned charEOF 都有很好的定义。根据语言环境,您还可能得到'ä' --> 'Ä' 等。tolower() 是小写的等价物。
  • @Lundin 1) 有趣的想法,分析将验证性能差异。有时考虑最小化分支会产生更高的速度。 2)现在考虑到顺序,我们现在也有细微的功能差异。 IAC,OP 的主要问题是函数原型。
  • @chux 不管是从 toupper() 调用 islower 还是硬编码到 toupper() 中都没有关系,你仍然有相同的开销代码。
【解决方案2】:

stricmpstrincmp 都是非标准函数。它们从未成为 C 标准的一部分。

【讨论】:

  • 如果它不是 c 标准的一部分,那么为什么我只会收到警告而不是错误?
  • 我的意思是,由于警告是隐式声明,而不是错误,因此确实以某种异常方式声明了该函数,对吧?
  • @walkerlala:因为 GCC 人决定将函数的隐式声明(或保留)作为警告而不是错误。使用-pedantic-errors 或更具体的-Werror=implicit-function-declaration
  • @walkerlala:除了#error 指令之外,C 标准只要求对任何违反规则的行为进行诊断。如果编译器的开发人员认为这样更方便,那么该诊断可能是一个非致命警告。 GCC 经常为在该语言的早期版本中合法的代码打印警告。教训:不要忽视警告。
猜你喜欢
  • 1970-01-01
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
  • 2011-08-20
  • 2011-02-09
  • 2012-12-29
  • 1970-01-01
  • 2011-02-07
相关资源
最近更新 更多