Are there any categories to characterize warnings? - c

My empirical assumption of what compilers warn about in C-Code was actually that they warn the kind of behaving which is implementation defined, or in cases where they detect an construct causing undefined behavior, which they support nevertheless (if they detect and wouldn't they'd throw an error over just warning).
After I had an discussion about this the final proof that I was wrong was this:
#include <whatever_this_needs.h>
int main()
{
int i = 50;
return 0;
}
The compiler obvious warned about i was declared but never used.
I wasn't thinking about this kinds of warning anymore, since I was seeing them more as kind of a tool.... an information.
While I would strictly dissociate this kind of warning from something that warns me about causing inportability or droping significance without explicit cast, it is still something that can cause confusion by compiler optimizations.
So I'm now interested: Are there any categorizations of warning types?
If no standards about it are existing, what are the categories, GCC groups their warnings in?
What I noticed so far (empirical again):
Warnings about:
implementation- / un- defined behaving
unnecessary code (targeted for optimization)
breaking of optional standards (i.e. MISRA or POSIX)
But especially the 2nd point bothers me, since there are constructs (i.e. strict aliasing rules) where optimization can even result in unpredicted runtime behaving, while most cases it just cuts away code that isn't used anyway.
So are my points correct? And what (additional) official categories are there you can 'typecast' warnings in, what are their characteristics, and what is their impact?

Warnings are beyond the scope of the C standard, so there are no requirements or specification for how they should behave. The C standard is only concerned about diagnostics, as in diagnostic messages from the compiler to the programmer. The standard doesn't split those up in errors and warnings.
However, all compilers out there use errors to indicate direct violations of the C standard: syntax errors and similar. They use warnings to point out things beyond what is required by the C standard.
In almost every case, a warning simply means "oh by the way, you have a bug here".
Regarding GCC (see this), it just categories warnings in:
Things that are direct violations against the C standard but valid as non-standard GNU extensions (-pedantic)
"A handful of warnings" (-Wall). Enable all warnings, except some...
"A few warnings more" (-Wextra)
Plus numerous individual warnings with no category.
There's no obvious logic behind the system.
Note that GCC, being filled to the brim with non-standard extensions, have decided just to give warnings instead of errors for some C standard violations. So always compile with -pedantic-errors if you care about standard compliance.
Regarding implementation-defined behavior: C contains a lot of this, it would get very tedious if you would get a warning for every such case ("warning: two's complement int used"...). There's no relation between implementation-defined behavior and compiler warnings.
Regarding any case of undefined behavior, the compiler is often unable to detect it, since the definition of UB is runtime behavior beyond the scope of the standard. Therefore the responsibility to know about and avoid UB lies on the programmer.

Related

Are there any examples of semantics non-preserving optimizations (except FP optimizations)?

It is considered that optimizations have semantics preservation property. However, floating-point (FP) optimizations may not preserve the semantics. Usually these FP-optimizations are the result of selection of non-strict FP models (examples: ICC, MSVC, GCC, Clang/LLVM, KEIL, etc.).
Out of curiosity, are there any examples of other semantics non-preserving optimizations?
There are, but you have to look hard to find them.
Try replacing a standard library function. If it doesn't do what the standard library function does, you may find that your code doesn't do what you expect, because the compiler assumes standard library functions do what the documentation says they do.
Also, mmap() a region at address zero. The compiler may omit code that accesses it because it assumes that code is unreachable because it dereferences a NULL pointer and thus undefined behavior. However, if that mmap() call succeeds, the behavior of dereferencing a zero (NULL is zero on most platforms) just became defined. gcc has a compiler option to tell it to stop doing that. Clang eventually caved to pressure to add it because it would otherwise miscompile the kernel. https://reviews.llvm.org/D47894#change-z5AkMbcq7h1h
Back in the 90s when the aliasing rules were just starting to become things, there were more examples, as the aliasing rules changed the definition of the language. But this is well-settled now.

What does uintptr_t have to do with strict aliasing?

I was doing some research on strict aliasing and how to handle it and found this commit on DPDK.
To fix strict aliasing (according to the comments), they are casting the void* parameters src and dst into uintptr_t. And then using the casted versions.
In my understanding, this should do nothing with the strict aliasing rule since there is no mention of casting to uintptr_t in the rule itself.
Would a cast to uintptr_t really help strict-aliasing? Or would this just fix some possible warnings from GCC?
Would a cast to uintptr_t really help strict-aliasing?
No, it would not.
Or would this just fix some possible warnings from GCC?
"Fix" in the sense of disguising the strict-aliasing violations well enough that the compiler does not diagnose them, yes, it might. And presumably it indeed did so for whoever made that change.
This is pernicious, because now, not only may the compiler do something unwanted with the code, but you cannot even prevent it from doing so by passing it the -fno-strict-aliasing option (or whatever similar option a different compiler might provide). Worse, it might work fine with the compiler used today, but break months or years later when you upgrade to a new version or when you switch to a different C implementation.
The "strict aliasing rules" specify situations where even implementations that are not intended to be suitable for low-level programming must allow for the possibility of aliasing between seemingly-unrelated objects. Compilers which are designed to be suitable for low-level programming are allowed to, and will, extend the language by behaving meaningfully--typically processing constructs "in a documented fashion characteristic of the environment" in more circumstances than mandated by the Standard, especially in the presence of constructs that would generally be useless otherwise.
Relatively few programs that aren't intending to access storage in low-level fashion will perform integer-to-pointer conversions. Thus, implementations that treat such conversions as an indication that they should avoid making any assumptions about the pointers formed thereby will be able to usefully process a wider range of programs than those which don't, without having to give up many opportunities for genuinely-useful optimizations. While it would be better to have the Standard specify a syntax for the purpose of erasing any evidence of pointer provenance, conversions through integer types presently work for almost all compilers other than clang.

Why missing terminating " character is a warning? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
When, for example, we compile the following code:
printf("hello);
we get a warning then an error about the missing " character. In my opinion, warnings inform us about a code that can be compiled but whose behaviour may be probably different from what the developper expects. Therefore my comprehension missed up two things:
Is there a complete code that can be compiled without errors while containing such a portion of code.
If such a code does not exist, why this missing character situation does not give us only an error (not a warning+error).
EDIT (I am doing my best to cope with off-topic votes recommendations):
1. Desired behavior : only one error diagnostic message, there is no need for a warning for the same thing.
Other related issues that do not let me accept the first answer:
2.1 Does printf_s() have the same issue? I tried to enable -c11 option with no success.
2.2 The historical reason to emit the warning does not seem to me to be plausible since why this double message was not used too in similar cases (old accepted constructions being forbidden in new c versions).
In my opinion, warnings inform us about a code that can be compiled
but whose behaviour may be probably different from what the developper
expects. Therefore my comprehension missed up two things:
Your opinion is irrelevant here, and neither the C standard nor the C++ standard distinguish different categories of diagnostic messages. That many compilers in fact do distinguish is an historically-based convention, albeit a widely observed one. What ultimately matters is what your compiler means by such a distinction (if indeed it makes one). On the other hand, and fortunately for you, GCC does adopt a convention similar to what you describe, as documented in its manual:
Errors report problems that make it impossible to compile your program. [...].
Warnings report other unusual conditions in your code that may indicate a problem, although compilation can (and does) proceed. [...]
(GCC 7.2 manual, section 13.9; the same or similar text appears also in earlier versions of the manual, back to at least v.4.)
Note well that the documentation frames the meaning of a warning slightly differently than you do: a GCC warning signals that compilation can proceed, but there is no assurance that it can complete successfully. If indeed it ultimately cannot then I would expect GCC, pursuant to its documentation, to also issue an error diagnostic. That is exactly what I observe with this test program, whether compiling as C or as C++:
#include <stdio.h>
int main(void) {
printf("hello);
}
I really think you are making far too much of the fact that GCC emits a warning in addition to an error in this case. That's an implementation quirk of no particular significance.
Is there a complete code that can be compiled without errors while containing such a portion of code.
It depends on exactly what you mean by that. Trivially, I could prefix the erroneous line in the above program with // to turn it into a comment, and that would make it perfectly valid C and C++ source. There are manifold other ways I could add to the given source without removing anything to make it valid -- some of them would even produce a program in which a printf() call is in fact performed.
I suppose that what you really want to know is whether there is code that would elicit the warning from GCC but not the corresponding error. To the best of my knowledge, modern GCC does not afford such code, but historically, GCC did allow it as an extension, in the form of embedded, unescaped newlines in string literals:
printf("hello);
Goodbye");
That behavior was already deprecated in GCC 3.2, and it was removed as early as GCC 4 (current is 7.2).
If such a code does not exist, why this missing character situation does not give us only an error (not a warning+error).
We can only guess, but it seems plausible that it derives from the historical existence of the language extension described above. And again, you are making far too much of this. GCC emits two diagnostics about the same problem -- so what? The ultimate purpose of the diagnostics is to help you figure out what is or may be wrong with your code, and the diagnostics GCC emits in this case do that job just fine.
Your compiler probably issues errors when it detects the program is ill-formed, and describes the immediate reason the program failed to be well formed at the location it happened.
This is often useless, because the mistake could have been many lines away.
It also issues warnings that are guesses (often educated guesses) what actually caused your problem. Maybe you forgot a ; on a previous line, failed to close a { or a (. The warning is not "this token is the point of error", but rather "this is where it all went wrong".
In reality, the C++ standard itself does not distinguish between warnings and errors; they are both diagnostics. It mandates some things cause diagnostics, and does not bar compilers from issuing additional diagnostics. Compilers are even free to compile ill formed programs with a warning.
I would expect an error for "newline in string", then a warning pointing at the open quote.

C standard prohibition on warnings by default

Seeing yet another question the answer to which would have been obvious had the questioner compiled with -Wall got me thinking.
Is there a 'C standard' based reason why -Wall cannot be enabled by default by the compiler?
As far as I know none of the major compilers do this (and certainly historically none of them did it), and I'd like to know whether this is adherence to the standard, or some other reason (inertia, back compatibility or whatever). Speculating as to the other reason is probably off-topic (opinion based), but I think asking whether a standard requires this behaviour is on-topic (factual).
Quoted from N1570 Annex I:
1 An implementation may generate warnings in many situations, none of
which are specified as part of this International Standard.
This implies that warnings are non-compulsory to compilers, so I don't think there would be any "C standard" based reasons.
Is there a 'C standard' based reason why -Wall cannot be enabled by default by the compiler?
I think that the answer to that is that no standard-based reason. The behavior of compiler switches is outside the scope of a language standard.
Beyond that, a compiler is (generally speaking) not required to produce diagnostics for things that are not specified to be compilation errors, so requiring such diagnostics be output "by default" is nonsensical.
And to be clear, these general statements apply in the case of the C language.
Besides the reason mentioned above, that the standard does not have specifications on warnings, make Wall default would be more a obstacle for many people because there are warnings that you actually don't want to turn on from time to time, such as warnings on unused variables/functions etc.
If you want to make it "by default", you can alias the compiler of your choice, take gcc as example, add following in your bashrc:
alias gcc="gcc -Wall"

The difference between -pedantic-errors and -Werror=pedantic in gcc

What is the difference between using -pedantic-errors and -Werror=pedantic in gcc?
According to the documentation of GCC there is a difference:
-pedantic-errors
Give an error whenever the base standard (see -Wpedantic) requires a diagnostic, in some cases where there is undefined behavior at compile-time and in some other cases that do not
prevent compilation of programs that are valid according to the
standard. This is not equivalent to -Werror=pedantic, since there are
errors enabled by this option and not enabled by the latter and vice
versa.
What errors are included by -pedantic-errors, but not by -Werror=pedantic?
What errors are included by -Werror=pedantic, but not by -pedantic-errors?
Any example of both types of errors?
A little insight as to why the two options exist separately in chapter 14:
Some ISO C testsuites report failure when the compiler does not produce an error
message for a certain program
ISO C requires a “diagnostic” message for certain kinds of invalid programs, but a
warning is defined by GCC to count as a diagnostic. If GCC produces a warning but
not an error, that is correct ISO C support. If testsuites call this “failure”, they should
be run with the GCC option ‘-pedantic-errors’, which will turn these warnings into
errors.
So it sounds like there's some ISO C rules that are not explicitly marked as invalid C but instead valid-ish C. These are the rules that -pedantic-errors makes into errors that -Werror=pendantic doesn't. You'll have to look at ISO C standard for more information on that.
As far as what errors are turned on/off as documented by GCC, there is but 1 that has -pendantic-errors explicitly:
-Wno-implicit-function-declaration
(C and Objective-C only)
This option controls warnings when a function is used before being declared. This warning is enabled by default in C99 and later dialects of C, and also by -Wall. The warning is made into an error by -pedantic-errors.
Note: however it seems that not all the authors of the manual have the same idea. In section 2 it talks about -pendantic-errors as if it WAS the same:
to obtain all the diagnostics required by the standard, you should
also specify ‘-pedantic’ (or ‘-pedantic-errors’ if you want them to be errors rather than
warnings).
So I believe you've discovered an editorial discrepancy.

Resources