10

Is the functions stricmp() and strnicmp() removed in C99? I always get warning implicit declaration of funtion stricmp() (and also strnicmp() ) when I try to compile it against C99. For example, the simple code below get me that warning.

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

When I try to compile this piece of code against C99(gcc -Wall -std=c99 main.c -o main), I get that warning. But when I compile it without the -std=c99, no warning will be thrown. However, even though there is warning of implicit declaration, my code still work out right.

Why is that? Is that a bug? If not a bug, then what is exactly the change of C99 which make that warning happen?

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
walkerlala
  • 1,599
  • 1
  • 19
  • 32
  • 8
    Those function have *never* been in the C standard, in fact there's no case-insensitive string comparison functions in the C standard. The `stricmp`, `strcasecmp` etc. functions are all extensions or defined by other standards (POSIX, WIndows, etc.) – Some programmer dude Jun 09 '15 at 13:46
  • See [g++ error: ‘stricmp’ was not declared in this scope (but OK for 'strcmp')](http://stackoverflow.com/q/1784767/1708801) – Shafik Yaghmour Jun 09 '15 at 13:53

2 Answers2

13

When code compiles with C99, it conform to the C99 standard, which does not have stricmp(). When code compile without C99 switch, it conforms to an unknown standard that implements stricmp(). (Given gcc without -std=c99, likely compiles to the C89/90 standard wihich allows implicit declarations.)

As @Joachim Pileborg commented, insensitive compares are not part of the C standard.

With C99 implicit functions require a diagnostic (a warning in this case). Without C99, the implicit use of the function generates no warning. The functions exists in this compiler's library - it is just a question of are the functions declared before use.

Easy enough to make your own:

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

Note: When coding and trying to make A-Z match a-z, string insensitive compare routines tend to work uniformly well. But when trying to to order strings, things quickly get out of hand. "abc" vs. "_bc" can come before or after the other depending on if compassion was done as upper or lower case. '_', in ASCII, exists between the upper and lower case letters. With internationalization and locale issues, the situation becomes more complex. My code example uses a round-trip of conversion to cope with issues where the number of uppercase char does not have a 1-to-1 mapping with lowercase ones. IMO the complexities of robust case insensitive compares obliges the use of UTF encoding and its case definition.


[Edit 2020]

To cope with those forlorned non-2's complement as well as 2's complement platforms, a code correction is warranted. Earlier code would fold a +0 and -0 into an unsigned 0. Only the +0 should convert to 0. Proper to read the data as unsigned char rather than signed char and convert.

Note: the proper handle in non-2's complement is mostly academic now.

// ca = (unsigned char) *a++;
ca = *((unsigned char *) a++);
// also cb
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • For a slight performance gain: `ca = *a; a++; if(islower(ca)) {ca = toupper(ca); }` and so on. Saves you some extra checks. – Lundin Jun 09 '15 at 14:24
  • I am sorry I can't exactly understand why you are using "toupper()" and "tolower()" in your function, though it works quite well – walkerlala Jun 09 '15 at 14:28
  • @walkerlala `toupper()` is a standard C function that converts an `int` to its upper case equivalent. `'a'` --> `'A'`, `'A'` --> `'A'`, `'0'` --> `'0'`, etc. It is well defined for all `unsigned char` and `EOF`. Depending on _locale_, you may also get `'ä'` --> `'Ä'`, etc. `tolower()` is the to lower case equivalent. – chux - Reinstate Monica Jun 09 '15 at 15:08
  • @Lundin 1) Interesting idea, profiling would validate performance differences. Consider sometimes minimizing branching yields higher speed. 2) Also we now have subtle functional differences now considering order. IAC, OP's primary issue is a function prototype one. – chux - Reinstate Monica Jun 09 '15 at 15:24
  • @chux toupper and tolower call islower and isupper respectively, by the standard spec. My code removes the need for the additional, implicit isupper call inside tolower. (And there's the minimal overhead of the tolower call itself, which will likely get optimized.) – Lundin Jun 09 '15 at 15:44
  • @Lundin Disagree "toupper ... call islower ..., by the standard spec" Do not find support for that in C99/C11. Certainly code could do that, yet another implementation may simple use a look-up table. With 8-bit `unsigned char`, the table may be as small as 257 bytes given "In all cases the argument is an `int`, the value of which shall be representable as an `unsigned char` or shall equal the value of the macro `EOF`. If the argument has any other value, the behavior is undefined." §7.4 1 – chux - Reinstate Monica Jun 09 '15 at 15:52
  • 7.4.2.2 **If the argument is a character for which islower is true** and there are one or more corresponding characters, as specified by the current locale, for which isupper is true, the toupper function returns one of the corresponding characters (always the same one for any giv en locale); **otherwise, the argument is returned unchanged**. – Lundin Jun 09 '15 at 15:58
  • @Lundin That part of the spec does not require `toupper()` to _call_ `islower()`, as your comment stated - only that `toupper()` have a particular functionality. Should you still disagree, suggest posting the question on SO as we are unlikely to agree. – chux - Reinstate Monica Jun 09 '15 at 17:59
  • I mean, why do you use "toupper()" and then "tolower()"? why not just "toupper()"? – walkerlala Jun 09 '15 at 22:54
  • @walkerlala In an A-Z world, there is no reason to use `tolower(toupper(ca))`, code could use `tolower(ca);` Think of a locale that had 3 e's: `E`, `É` (both with `tolower()` go to `e`) and `e`. If code only uses `toupper()`, `E`, would not compare case-lessly to `É`. As mentioned in my answer, not all locales have a nice 1-to-1 mapping of lower and upper case letters. Some have a 2-to-1 in one direction (e. g. `tolower()`), but of course cannot have a 1 to 2 mapping in the other direction. C does `A-Z` to/from `a-z` fine, but for the rest of world, C has issues. – chux - Reinstate Monica Jun 09 '15 at 23:14
  • @walkerlala Further: case-less comparison outside `A-Z` is a mud-hole of language and regional variations. Suspect that is why standard C does not define `stricmp()` and family. I use round trip (toupper and tolower) as that folds more like-letters to compare the same. – chux - Reinstate Monica Jun 09 '15 at 23:19
  • totally uderstand. And suggest edit , since you seem to mistake "ca" for "c1" – walkerlala Jun 09 '15 at 23:29
  • 1
    @chux It doesn't matter in the slightest if islower is called from or hardcoded into toupper(), you still have the very same overhead code. – Lundin Jun 10 '15 at 06:11
5

stricmp and strincmp are both non standard functions. They have never been a part of the C standard.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
haccks
  • 104,019
  • 25
  • 176
  • 264
  • If it is not part of c standard, then why do I get only warning, rather than error? – walkerlala Jun 09 '15 at 13:52
  • I mean, since that the warning is implicit declaration, not error, that function is indeed declared, in some abnormal way, right? – walkerlala Jun 09 '15 at 13:55
  • 2
    @walkerlala: Because the GCC people decided to make (or leave) implicit declaration of functions a warning and not an error. Use `-pedantic-errors` or more specifically `-Werror=implicit-function-declaration`. – cremno Jun 09 '15 at 14:00
  • 3
    @walkerlala: Apart from the `#error` directive, the C standard only requires a *diagnostic* for any violation of a rule. That diagnostic may be a non-fatal warning if the developers of the compiler decide that's more convenient. GCC often prints warnings for code that would have been legal in earlier versions of the language. Lesson: Do not ignore warnings. – Keith Thompson Jun 09 '15 at 14:30