Why does C code allow this code to be compiled without errors?

Here is a piece of code that seems to be accepted without errors:

#include <stdio.h> #include <string.h> int main() { if (strcmp(1, 2)) printf(3); } 

Compiling with clang -std=c11 -Weverything generates 4 warnings:

 badstrcmp.c:5:16: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Wint-conversion] if (strcmp(1, 2)) ^ /usr/include/string.h:77:25: note: passing argument to parameter '__s1' here int strcmp(const char *__s1, const char *__s2); ^ badstrcmp.c:5:19: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Wint-conversion] if (strcmp(1, 2)) ^ /usr/include/string.h:77:43: note: passing argument to parameter '__s2' here int strcmp(const char *__s1, const char *__s2); ^ badstrcmp.c:6:16: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Wint-conversion] printf(3); ^ /usr/include/stdio.h:259:36: note: passing argument to parameter here int printf(const char * __restrict, ...) __printflike(1, 2); ^ badstrcmp.c:6:16: warning: format string is not a string literal (potentially insecure) [-Wformat-security] printf(3); ^ badstrcmp.c:6:16: note: treat the string as an argument to avoid this printf(3); ^ "%s", 4 warnings generated. 

My question is Why does standard C allow it to be compiled? . Such problems should be diagnosed as errors, and the code should be denied. Why does standard C allow translation of a program?

+5
source share
5 answers
 #include <stdio.h> #include <string.h> int main() { if (strcmp(1, 2)) printf(3); } 

The call to strcmp and printf , as they pass arguments of the wrong types (and there is no implicit conversion), are violation of restrictions.

The C standard requires at least one diagnostic message for any program that violates a restriction or syntax rule. A warning is a truly reliable diagnostic message regarding the standard.

This standard says (quoting the N1570 draft of C11, section 5.1.1.3):

The corresponding implementation must give at least one diagnostic message (defined according to the implementation) if the translation unit for preprocessing or the translation unit violates any syntax rule or restriction, even if the behavior is also explicitly specified as undefined or determined by the implementation. Diagnostic messages should not occur under other circumstances.

The only case where the standard actually requires that the source file be rejected is when it contains the #error directive. Section 4, paragraph 4:

An implementation should not successfully translate preprocessing which contains the #error preprocessor directive if it is part of a group that is skipped by conditional inclusion.

I personally would prefer gcc and clang to reject programs that violate rules or syntax restrictions, but, as I said, non-fatal warnings are allowed as standard. If you want to reject such programs, you can use various parameters, for example -std=c11 -pedantic-errors . Note that gcc and clang do not fully comply with the C standard by default, but these non-fatal warnings are not an example of such a mismatch.

+3
source

Your question seems to be based on the incorrect premise that C Standard somehow "allows you to compile this code." In fact, C Standard does not have such a concept as "permission or inability to compile code."

If the code is invalid, the Standard requires compilers to inform you of this with diagnostic messages. The standard does not require compilers to refuse to compile your code. They can still progress and compile it in a certain way.

Your code is clearly invalid according to the C standard. The standard C language does not allow implicit conversion of integers to a pointer. And your compiler clearly told you about this through diagnostic messages. This is enough to ensure that the compiler complies with the requirements of the standard.

After that, all bets are disabled. Your compiler can compile it into "something", but it is not a corresponding C program. Its behavior is not determined by the language.

As for the format of the received diagnostic messages (and whether they are “warnings” or “errors”), this is a question for your compiler. In C, this is a quality implementation problem. C Standard has nothing to do with it.

You can ask clang to report violations of the C language restrictions as "errors" by specifying the -pedantic-errors flag. This is not ideal for this purpose, but it will cause the compiler to refuse to compile your code (if you need it).

+6
source

and the code must be rejected.

Good thing is a big guess.

To actually specify a standard:

an implementation can freely perform any number of diagnostic operations if the actual program is still correctly translated. It can also successfully convert an invalid program.

( 5.1.1.3 note 9 )

The standard does not establish significant restrictions on what the compiler should do when an error occurs, precisely for the reason that in many situations and on many platforms "errors" can really be clearly defined (by implementation) of the extension of behavior. It may also be better, from the point of view of providing useful information to the developer, to continue translating and collecting other errors or information in the next part of the program than to abandon the first incredibly insignificant, still syntactically valid complex point.

He also prefers not to make too many assumptions about what “translation” includes (stage 7 of translation is basically just “something happens here”). There are no concepts of “machine code” (with the exception of extensions like J.5.7 ) in a strictly standard version of the language, for example, since the standard cannot prevent the compiler from emitting it.

+5
source

On the one hand, the standard explicitly allows conversion of integers to a pointer type (see standard C99 ):

6.3.2.3 Pointers ... (5) An integer can be converted to any type of pointer. In addition, as previously indicated, the result is determined by the implementation, it may not be correctly aligned, it may not point to an object of a reference type, and may be a trap representation .56)

On the other hand, the standard requires explicit coercion in such situations:

6.5.4 Role operators ... (3) Conversions that include pointers other than those permitted by the restrictions of 6.5.16.1 must be specified using explicit casting

So printf(3) clearly not correct, but is there an error or a warning - in this case, given the compiler.

+4
source

If you want not to compile such code, use -Werror as an additional flag that turns each warning into error compilation and your code will not be compiled.

+3
source

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


All Articles