Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't C compilers warn about incompatible types with literal strings? [duplicate]

The following program provokes systematic segmentation fault due to undefined behavior (trying to modify a string literal):

int main() {
  char *s = "immutable";
  s[0] = 'a';
  return 0;
}

Still, there seems to be absolutely no way to tell GCC/Clang to emit even the slightest warning about it (-Wall -Wextra -pedantic -std=c11 don't do anything).

Especially for beginners, this kind of situation would be useful to inform about. Even for non-beginners, in some slightly less obvious situations it could be helpful:

void f(char *s) {
  s[0] = '0';
}

int main() {
  char *s = "immutable";
  f("literal"); // oops
  f(s); // oops
  return 0;
}

Besides, this would help enforce some const-culture in C programming.

Why are such cases deliberately ignored? Does the standard actively prohibit diagnostics from being emitted in such cases, or is it mostly for backwards-compatibility (trying to enforce them now would generate too many warnings)?

like image 612
anol Avatar asked Sep 06 '17 07:09

anol


People also ask

How does GCC treat warning errors?

The warning is emitted only with --coverage enabled. By default, this warning is enabled and is treated as an error. -Wno-coverage-invalid-line-number can be used to disable the warning or -Wno-error=coverage-invalid-line-number can be used to disable the error. Suppress warning messages emitted by #warning directives.

Which GCC flag is used to enable all compiler warning?

gcc -Wall enables all compiler's warning messages. This option should always be used, in order to generate better code.

What is Werror?

-Werror= Make the specified warning into an error. The specifier for a warning is appended, for example -Werror=switch turns the warnings controlled by -Wswitch into errors.

Which option can be used to display compiler warnings?

You can use a #pragma warning directive to control the level of warning that's reported at compile time in specific source files. Warning pragma directives in source code are unaffected by the /w option.


1 Answers

TL;DR C compilers do not warn, because they do not "see" a problem there. By definition, C string literals are null terminated char arrays. It's only stated that,

[...] If the program attempts to modify such an array, the behavior is undefined.

So, in the compilation process, it is not known to the compiler that a char array should behave as a string literal or string. Only the attempt to modification is prohibited.

Related read: For anybody interested, see Why are C string literals read-only?

That said, I am not very sure whether this is a good option, but gcc has -Wwrite-strings option.

Quoting the online manual,

-Wwrite-strings

When compiling C, give string constants the type const char[length] so that copying the address of one into a non-const char * pointer produces a warning. These warnings help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using const in declarations and prototypes. Otherwise, it is just a nuisance. This is why we did not make -Wall request these warnings.

So, it produces a warning using the backdoor way.

By definition, C string literals (i.e., character string literals) are char arrays with null terminator. The standard does not mandate them to be const qualified.

Ref: C11, chapter

In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence. [....]

Using the aforesaid option makes the string literals const qualified so using a string literal as the RHS of assignment to a non-const type pointer triggers a warning.

This is done with reference to C11, chapter §6.7.3

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. [...]

So, here the compiler produces a warning for the assignment of const qualified type to a non-const-qualified type.

Related to why using -Wall -Wextra -pedantic -std=c11 does not produce this warning, is, quoting the quote once again

[...] These warnings help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using const in declarations and prototypes. Otherwise, it is just a nuisance. This is why we did not make -Wall request these warnings.

like image 120
Sourav Ghosh Avatar answered Oct 22 '22 05:10

Sourav Ghosh