Is there a way to disable main() prototype checking in clang?
I mostly using unsigned int type for argc and it was perfectly fine in gcc, but clang complains (it says argc should be int) and not with just a warning but with a non-compilable error.
I know that some standards says the same, but I also know that unsigned int is okay in this case and don't want to mess with this nonsense.
clang uses diagnostic categories. For displaying all of them use:
# clang --print-diagnostic-categories
Then for identifying this specific warning category use
# clang -fdiagnostics-show-category=id
It will display something as:
... return type of 'main' is not 'int' [-Wmain-return-type,2] ...
Rebuild with
# clang -Wno-main-return-type
should solve your problem.
Best regards
Related
I´m having troubles understand a compiler warning that we have in our code. The code we have are similar to the one in this example that give the warning (-Wchar-subscripts). We are using ARM gcc 9.2.1 embedded and newlib as standard library.
#include <ctype.h>
int main ()
{
char str[]="Example string\n";
int i = isspace(str[1]); // Warning
char c=str[1];
i = isspace(c); // No warning
i = isspace((unsigned char)str[1]); // No warning
}
Example in godbolt
From what I have understood the implementation of isspace can be via array indexing. Hence the warning. But in that case shouldn't both 1 and 2 give the warning? Why is it only the first one that gives the warning?
We solved our code by adding a cast but I'm not really satisfied until I have understood why it helps.
This appears to be the very same bug as discussed in Bugzilla here Bug 95177 - error: array subscript has type char. Basically gcc is inconsistent in its diagnostics and this behavior only appeared in later versions.
As discussed in that thread, passing char to the ctype.h functions could in theory be a problem in case the char would contain anything unknown. These functions are defined as expecting the input to be something representable as unsigned char, see C17 7.4:
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
Therefore int i = isspace((unsigned char)str[1]); makes the warning go away.
But the warning is as you can tell inconsistent. Which could possibly be explained by when you are using ctype.h, the compiler could sometimes be picking a macro and sometimes a function.
Just disable it and regard it as a false positive. According to the Bugzilla log above, this should now have been fixed very recently. gcc (trunk) and gcc >10.3 doesn't give this warning any longer.
The difference in warning messages between isspace(str[1]) and isspace(c) is caused by a bug in GCC’s feature to suppress warning messages in system headers.
Consider this code:
#include <ctype.h>
int foo(char c)
{
return isspace(c);
}
int bar(char c)
{
return
((((_ctype_)+sizeof(""[
c
]))[(int)(
c
)])&010);
}
The code in bar is the result of applying macro replacement to the code in foo (it was obtained by compiling with -E to show the result of preprocessing). So these two functions have identical code after macro replacement and should have identical semantics. Yet the second code gets a warning and the first code does not. Therefore, GCC’s reporting is not based solely on the C semantics of the code.
GCC has a feature to suppress warnings in system header files. When this feature is disabled (by using -Wsystem-headers), both functions get a warning message. Therefore, the warning that occurs with isspace(str[1]) but not with isspace(c) is due to a failure of the feature to suppress warning messages in system headers. That is, it is a bug in GCC.
For confirmation, using -Wsystem-headers with the original code in the question yields warning messages for both isspace(str[1]) and isspace(c).
Are there any rules at a function-level for what numeric types are allowed to be passed to it without a warning? For example, if we take the following two functions:
void take_int(int n){};
void take_double(double n){};
And calling it as:
take_int(4); # as intended
take_double(4.0); # as intended
take_double(4); # have to up-convert int to double
take_int(4.0); # have to down-convert double to int
When would this raise a warning or not be acceptable (ignoring what the actual function does with the values)?
The code you wrote is valid C, so it should be accepted by any compiler.
I tried your code in some recent versions of clang and GCC using Compiler Explorer, with the -Wall -Wextra --pedantic warning options, and none of them gave warnings.
However, the C standard does not specify what warnings a compiler should give, so the warnings you get will depend on what specific compiler you are using, and what version.
I have been reading through the documentation for strtoul()/strtoull() from here, and under the "Conforming To" section towards to bottom, it makes these two points:
strtoul(): POSIX.1-2001, POSIX.1-2008, C89, C99 SVr4.
strtoull(): POSIX.1-2001, POSIX.1-2008, C99.
These two lines, in addition to other references throughout the document indicate to me that the function strtoull should not be available when compiling a program using the c89/c90 standard. However, when I run a quick test with gcc, it allows me to call this function, regardless of the standard that I specify.
First, the code I am using to test:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
unsigned long long x;
const char *str = "1234";
x = strtoull(str, NULL, 10);
printf("%llu\n", x);
return 0;
}
And here is my compilation command:
gcc test.c -std=c89 -pedantic -Wall -Wextra
Now, in fairness it does warn me of the compatibility issue:
test.c: In function ‘main’:
test.c:6:16: warning: ISO C90 does not support ‘long long’ [-Wlong-long]
unsigned long long x;
^~~~
test.c:9:6: warning: implicit declaration of function ‘strtoull’; did you mean ‘strtoul’? [-Wimplicit-function-declaration]
x = strtoull(str, NULL, 10);
^~~~~~~~
strtoul
test.c:11:9: warning: ISO C90 does not support the ‘ll’ gnu_printf length modifier [-Wformat=]
printf("%llu\n", x);
^~~~~~~~
These warning messages are exactly what I would expect given the documentation. It notifies me that the function I have specified cannot be found, and even that the C90 standard doesn't support unsigned long long. However, when I attempt to run this code, it works just fine, with no crashing or other types of errors. It prints the value 1234, as desired. So, based on this experiment, I have a few questions that I was hoping someone more seasoned than I could answer.
Is this a matter of me not providing the necessary compilation flags to enforce the 'strict' c98 standard?
Is this a case of me misunderstanding the documentation, or is there some documentation for gcc itself that I should refer to? And, if so, where could I find it?
Is there something fundamental about the compiling/linking process that I am not understanding, which explains this issue?
Why would I be warned of an incompatibility, even warned that the function I am calling does not exist, but the code still works with no issue?
Does this experiment imply that the -std=c89 -pedantic flags do not actually enforce the C89/C90 standard?
As a final note, I am not trying to say I want to use this function in C89, I was just curious about the compatibility restriction, and then confused about the answer.
Thanks in advance for any responses!
From a C89/C90 compiler's point of view, the only thing wrong with your code is the use of unsigned long long which looks like a syntax error. The standard requires only that the compiler produce a "diagnostic" in this case, and GCC has done so with its "ISO C90 does not support long long" warning. There is no requirement that this error should be fatal, and the compiler can decide to handle the code some other way if it wants. GCC obviously chooses to understand it as the long long type which it supports as an extension to C89.
The use of strtoull then just looks like some function that you made up, as C89 had no way of knowing that this name would be special in some future version of the standard. (Well, they did specify that more functions starting with str could be added to <string.h> in the future, but that doesn't make your code illegal for C89.) You haven't declared it, but C89 allowed implicit declarations, so it's understood to be declared as int strtoull();, i.e. returning int and with unspecified arguments. AFAIK no diagnostic was required for implicit declarations, but GCC chooses to issue one anyway. So it's treated like any other call to a function not defined in this source file, and the compiler presumes that some other part of your program (including the libraries you use) will define it.
And in fact some other part of your program does define it, namely libc, since your libc conforms to C99 and later. (You know, hopefully, that libc is not part of GCC.) C library authors generally don't provide a version of the library that only includes functions from a particular standard version, since having so many different libraries around would be awkward and inefficient. So linking succeeds.
Note, though, that because of the implicit declaration, the program may not actually work correctly. The compiler will generate code incorrectly assuming that strtoull returns int, which depending on your system's calling conventions, may cause all sorts of problems. On x86-64, it means that your program will only look at the low 32 bits of the result and will sign-extend them to 64 bits. So if you try to convert a number that fits in 32 bits but would not fit in long long, you'll get the wrong result. Example.
If you want a program that would work on a system that only supports C89 and nothing else, it's your responsibility to look at the diagnostics issued by the compiler and fix the corresponding problems. The -pedantic-errors option mentioned in comments can help with this, as it causes compilation to fail when such diagnostics are issued.
It would also help if you could find a C89-only libc, but that's not GCC's problem. But its implicit declaration warnings do give you some assistance in noticing that you have called a function which you may not have intended for your program to define.
As a final point, it's historically been part of GCC's design philosophy that they don't think "enforcing the standard" is really part of what they want to do. They saw their goal as writing a compiler that helps people write and compile programs that are useful, not a linter that checks for conformance with coding standards; they figured the latter should be a separate project, and not one that they were interested in. As such, they were liberal in providing extensions to the standard language, and not particularly diligent in providing ways for programs to avoid using them. They did provide the -pedantic option but apparently with some reluctance, as you can tell from the derogatory name.
online compiler: https://www.onlinegdb.com/online_c_compiler#
Why does this compiler let me compile a code without the functions before the main function? Shouldn't it be an error?
In the old C there was a thing called implicit function declaration. When a call to an undeclared function appeared it was assumed to be of type int(), i.e. a function that takes an unspecified number of parameters and returns an int.
int main()
{
foo(); // foo is implicitly declared as `int foo()`
}
Since C99 this is illegal. Turn on compiler warnings and use a proper language dialect.
There are more quirks like this from the old age. For instance you could declare function arguments without a type and the type would be implicit int:
int test(a) // a type is implicitly int
{
a = 11;
return a;
}
The above doesn't even generate any warnings unless -pedantic is used
If you want to go even crazy compile this:
double test(a, b)
int a;
double b;
{
a = 11;
b = 3.14;
return a + b;
}
This is an old way (K&R times) of declaring variables and I didn't find any flags to trigger a warning.
So yeah, old C is strange and finds its way to creep in even today.
C compilers often default to earlier-than-the-last C language standard, and go easy with errors that were historically tolerated by the language.
Your error is one of those that used to be regular legal code 30 years ago.
You want to specifically and explicitly instruct your compiler to be strict with your code by supplying appropriate options. For a reasonably recent build of gcc it would be -std=c11 -Wall -Werror or a similar set of options.
The online IDE in question doesn't appear to support passing user-specified options to the underlying compiler, so you're out of luck here. Use your own computer to run a compiler, or find a better online IDE.
Preamble: My C may be fairly rusty; I first started writing C programs in somewhere around 1993 -- compilers may have been different back then, but I recall that when one attempted to refer to a C function that was not declared, the compiler would abort. This is from memory.
Currently, I am perplexed as to why GCC (4.4.3) is so forgiving on me when I [intentionally] mismatch or omit declaration of bar below, with its definition in bar.c. Because the compiler does not warn me, the program proceeds to a fatal addressing error at runtime -- since bar wants an address and is given an integer, it ends up de-referencing that integer as an address.
A strict compiler, or so I would think, would abort on me with an error. Am I missing something? My build command line is as follows:
cc -o foobar -g -Wall -std=c99 -fexec-charset=ISO-8859-1 -DDEBUG foo.c bar.c
With foo.c:
int main() {
int a;
bar(a);
return 0;
}
and bar.c:
void bar(int * a) {
*a = 1;
}
I have intentionally omitted declaration of bar and, as mentioned, intentionally pass it an integer (could be anything really) instead of an address that its actual definition would otherwise mandate. Because $(CC) does not stop me, I end up with a segmentation fault (x86, Ubuntu 10.04). I am aware that a compliant C (C99?) compiler would implicitly create an int bar(void) declaration for bar if none otherwise found, but in this case that's obviously not what I want at all!
I want to protect myself from the kind of errors -- where I make the human mistake of mismatching declarations and definitions or omitting the former altogether.
I tried to instead just invoke the compiler without the linking step (with the -c switch) -- but it doesn't matter as compiling still succeeds with warnings. The linker might complain though, but I want the compiler to stop me before that happens.
I do not actually want to turn all my warnings into errors (e.g. with -Werror), because:
I could have included the wrong float bar(double a); at the top of foo.c, which would eliminate the warning altogether, but doesn't change the fact that the resulting program crashes; alas, a program that compiles successfully without warnings (even with the -Wall switch) but still is faulty
I have and will have other types of warnings that should stay warnings and not prevent successfully building the program
It would be dealing with the effect of the problem, rather than the problem itself
It's not just the types of warnings, but also particular instances thereof; I wouldn't want to turn a specific warning into an error because in some instances that would not be applicable; this would be too "coarse" of a solution which doesn't take into account the specifics of and the context in which the warning occurred
To turn this warning into an error when compiling with gcc, pass the switch -Werror=implicit-function-declaration to the compiler.
Trying to answer your "why" question: yes, it might look odd that this is by default a warning and not an error. This is for historical reasons. For details, see e.g. Why does/did C allow implicit function and typeless variable declarations?, or read it in Ritchie's own words at http://cm.bell-labs.com/who/dmr/chist.html.
You could probably force additional warnings for gcc:
-Wmissing-prototypes
-Wmissing-declarations
Using both (along with -Werror) will probably help you to avoid such situations, but require some more code writing.
Inspired by this.
EDIT: Example
// file: mis1.c
int main(void)
{
int a;
bar(a);
return 0;
}
// file: mis2.c
#include <stdio.h>
double bar(double a)
{
printf("%g\n", a);
return a;
}
Compiling with gcc 3.3.4 (DJGPP) as:
gcc -Wall -Wmissing-prototypes -Wmissing-declarations -Werror mis2.c mis1.c -o mis.exe
Compiler output:
mis2.c:5: warning: no previous prototype for `bar'
mis1.c: In function `main':
mis1.c:6: warning: implicit declaration of function `bar'
Fix? #Include the following file in both files:
// file: mis.h
extern int bar(int);
Recompiling you get:
mis2.c:6: error: conflicting types for `bar'
mis.h:3: error: previous declaration of `bar'
Fix? Define and declare bar everywhere in the same way, correct, for example, mis.h:
// file: mis.h
extern double bar(double);
Likewise you could change bar() in mis2.c to match that of mis.h.
From the gcc docs on warnings:
-Wimplicit-function-declaration (C and Objective-C only)
Give a warning whenever a function is used before being declared. In C99 mode (-std=c99 or -std=gnu99), this warning is enabled by default and it is made into an error by -pedantic-errors. This warning is also enabled by -Wall.
...
-pedantic-errors (my emphasis) Like -pedantic, except that errors are produced rather than warnings.
...
-pedantic
Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.
It looks to me that -pedantic-errors will do what you want (turn these warnings into errors), however it sounds like it will also turn on a host of other checks you may or may not want. =/
The closest I found to a solution to my problem was to simply use the flag -combine which indirectly causes the compiler to abort compilation when attempting to call a function that is missing a prototype or where prototypes mismatch or do not match the definition.
I am afraid it has drawbacks though. Since input files now are combined in one compilation run, one ends up with a single object file, which has some implications of its own. In short, -combine does something more than just fix my problem, and that may be a problem in itself.
You can turn all warning to error with
cc [..] -Werror [..]
. This will partially solve your problem.
I could have included the wrong float bar(double a); at the top of foo.c, which eliminates the warning altogether, but doesn't change
the fact that the resulting program crashes. Alas, a program that
compiles successfully without warnings (even with the -Wall switch)
and beautifully crashes at runtime.
Herefore it is essential, additional to other measures, to include the same header file (including the prototype) in foo.c and bar.c. This ensures that the correct prototype is applied at both places.