Why is the const determinant warning dependent on the contents of the variable, and not on the type?

I discovered weird behavior from gcc with the following code:

 #include <stdio.h> #include <string.h> int main(void) { const char str[] = "This string contains é which is a multi-byte character"; const char search[] = "Ʃ"; char * pos = strstr(str, search); printf("%s\n", pos); return 0; } 

The compiler generates a warning:

 $ gcc toto.c -std=c99 toto.c: In function 'main': toto.c:8:18: warning: initialization discards 'const' qualifier from pointer target type [enabled by default] 

But if I change the contents of search :

 const char search[] = "é"; 

The compilation itself does not cause any warning: why?

Note: I have the same behavior if I exchange Ʃ and é : if the character in search not in str , I get a warning.

+6
source share
2 answers

This seems to be a bug in gcc, fixed in a later release.

Here is a small program that I wrote to illustrate the problem.

 #include <stdio.h> #include <string.h> int main(void) { const char message[] = "hello"; #ifdef ASCII_ONLY const char search_for[] = "h"; #else const char search_for[] = "Ʃ"; #endif char *non_const_message = strstr(message, search_for); if (non_const_message == NULL) { puts("non_const_message == NULL"); } else { puts(non_const_message); } } 

When I compile it with

 gcc -DASCII_ONLY -std=c99 -pedantic-errors cc -oc 

(using gcc 4.8.2 on Linux Mint 17), it compiles without diagnostic messages, and the resulting program prints

 hello 

(I use -pedantic-errors because it causes gcc (attempt) to be a compatible ISO compiler.)

When I discard the -DASCII_ONLY , I get a compile-time error message:

 cc: In function 'main': cc:11:31: error: initialization discards 'const' qualifier from pointer target type char *non_const_message = strstr(message, search_for); 

The strstr function returns a result of type char* , not const char* . It takes two arguments const char* , and with the right search string, it can return the value of its first argument. This means that he can silently reject the const argument of his argument. I believe this is a flaw in the C standard library, but we probably stick to it. According to C implementations, there is no way to “fix” this flaw if they want to stay consistent; they can warn of the dangerous use of strstr , but they cannot reject a different legal code.

(The disadvantage could be avoided by dividing strstr into two functions with different names, taking const char* and returning a const char* , and the other take char* and return a char* . The 1989 ANSI Committee did not take the opportunity to do this, because because they didn’t think about it or because they didn’t want to break the existing code. C ++ solves it with two overloaded versions of strstr that were not possible for C.)

My first assumption was that gcc “magically” does something similar to what C ++ does, but examples that discard const using only ASCII characters do not trigger a diagnostic message. As my test program shows, the problem is triggered using a non-ASCII character in the string literal ( "Ʃ" , not "h" ).

When I use gcc 4.9.1 (which I installed from the source) and not gcc 4.8.2 (the default version installed on my system), the problem disappears:

 $ gcc -DASCII_ONLY -std=c99 -pedantic-errors cc -oc && ./c hello $ gcc -std=c99 -pedantic-errors cc -oc && ./c cc: In function 'main': cc:11:31: error: initialization discards 'const' qualifier from pointer target type char *non_const_message = strstr(message, search_for); ^ $ gcc-4.9.1 -DASCII_ONLY -std=c99 -pedantic-errors cc -oc && ./c hello $ gcc-4.9.1 -std=c99 -pedantic-errors cc -oc && ./c non_const_message == NULL $ 

I no longer tracked the error, but you could find it in the list of gcc errors installed between 4.8.2 and 4.9.1.

For the code in question, you can avoid the problem by specifying pos as const char* rather than char* . It must be const char* anyway, as it points to an object that was defined as const .

+3
source

Here are a few things going on.

gcc header files instruct gcc to use the built-in optimized strstr() , which the compiler knows what it is. Purely from a language point of view, strstr() is just some library function that, theoretically, the compiler does not know. But gcc really knows what it is.

gcc optimized version of strstr() , if the string parameter is char * , strstr() returns a char * ; but if the string parameter is const char * , strstr() returns a const char * , which makes sense.

So in your case strstr() returns a const char * , which leads to an obvious error, assigning the non-constant char * .

What also happens is that in the second part of your gcc question, it turns out that the line exists and optimizes all this; but in this case, this should also lead to the conversion of const char * to char * and a warning. Not sure about that.

+7
source

Source: https://habr.com/ru/post/974547/


All Articles