I have the following C code with a missing function
test1.c
#include <stdio.h>
int main(){
Log("hello");
return 0;
}
Compiling it to an object file with gcc -c test1.c produces an object file with a warning (linking will fail of course).
Compiling the same code (with iostream instead of stdio.h) to an object file using g++ doesn't even compile and it complains by error: use of undeclared identifier 'Log'.
Why didn't gcc stop compilation but g++ did?
C++ does not permit undeclared functions to be called. However, prior to C99, undeclared functions are sometimes permitted in C. Therefore, the code has to result in compile time error in C++, but it can succeed in compiling in C89 (although linking will find no definition of the hypothetical Log.)
Since C99, undeclared functions are not permitted.
Because C and C++ are different languages with different rules.
There is no such thing as an implicit function declaration in C++ and there never has been in any version of the language standard. The shown program is ill-formed.
Non-declared functions can be called in old versions of C. However, since C99 it has been ill-formed in that language as well.
Related
I'm using Clang v3.7.0 with Mingw-w64 5.1.0 and GCC 5.1.0, all 64-bit, on Windows 10. My goal is to use a set of Clang and GCC options that will give me the best chance of detecting potential C89 and C++98 language standards portability issues across many different compilers. For example, for C I have been using the following GCC command line with pretty good success:
gcc -c -x c -std=c89 -pedantic-errors -Wall -Wextra -Wno-comment -Wno-parentheses -Wno-format-zero-length test.c
However, I recently tried it with Clang and got a different result. Here is my sample test code:
int main(void)
{
int length = (int)strlen("Hello");
return 0;
}
With Clang I get the following error, whereas with GCC I get the same basic thing, but it flags it as a warning instead:
test.c:3:22: error: implicitly declaring library function 'strlen'
with type 'unsigned long long (const char *)'
int length = (int)strlen("Hello");
If I remove the -pedantic-errors option, or just change it to -pedantic, Clang then only flags it as a warning, which is what I actually want. However, according to the GCC documentation the -pedantic-errors option causes warnings that are considered language extensions to be flagged as errors, but not using a prototype for a function is not an extension in C89. So, I have three basic questions:
Has Clang changed the meaning of -pedantic-errors from the meaning used by GCC, or am I misinterpreting something?
What is the best set of options that will enforce adherence to the selected standard and will issue errors for all non-conforming code?
If I continue to use -pedantic-errors with Clang is there a way to get it to issue a warning instead of an error in specific cases? In another posting on this site an answer was given that said to use the following, where foo is the error:
-Wno-error=foo
If that is a correct approach, what do I actually use in place of foo for an error like I'm getting since there is no actual error number indicated? I can't believe it actually wants all of the following:
-Wno-error=implicitly declaring library function 'strlen'
with type 'unsigned long long (const char *)'
Your code is invalid, and the behavior is undefined, so the compiler can do anything also when compiling. The implicitly declared int strlen(char*) is not compatible with size_t strlen(const char *).
Has Clang changed the meaning of -pedantic-errors from the meaning used by GCC, or am I misinterpreting something?
As I read it, yes. From clang documentation:
-pedantic-errors
Error on language extensions.
In GCC:
-pedantic
Issue all the warnings demanded by strict ISO C and ISO C++ [...]
-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.
Clang errors on extensions.
GCC errors when standard explicitly requires it and in other "some cases".
This is a different, it is a different set of errors. Standard may not require a diagnostic, but it's still an extension - GCC will be silent, Clang will error.
What is the best set of options that will enforce adherence to the selected standard and will issue errors for all non-conforming code?
The first answer that comes to mind is: "none". Compiler inherently use "implementation-defined behavior" and extension, because they are meant to compile the code in the first place, not meant to not compile non-conforming code. There are cases where the code is conforming, but still the behavior differs between compilers - you can explore such a case here.
Anyway, keep using -pedantic-errors, as it seems to work in detection of non-conforming code. Your code is invalid, the behavior is undefined, so your code is non-conforming, so clang properly detects it. Also use linters and sanitizers to detect other cases of undefined behavior.
If I continue to use -pedantic-errors with Clang is there a way to get it to issue a warning instead of an error in specific cases?
Use -fno-builtin.
Let's analyze the following code example:
int main() {
return func();
}
int func() {
return 1;
}
Clang will report error:
/private/tmp/src.cpp:2,9 - Error - use of undeclared identifier 'func'
But i can find lot's of such errors in wide used examples, f.e. some arduino sources:
https://github.com/firmata/arduino/blob/master/examples/StandardFirmata/StandardFirmata.ino
line 235 : disableI2CPins(); // invocation (before definition, no declaration before)
...
line 651 : void disableI2CPins() { .. } // definition
Though function is used before defined that code can be compiled with GCC successfully. How that can be? Is it different Clang and GCC behavior? Are there any flags to allow this for Clang?
PS. Here is successful command line to compile the code used by Arduino IDE:
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++
-c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10600 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino
-I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/variants/mega
-I/Applications/Arduino.app/Contents/Resources/Java/libraries/Servo/src
-I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/libraries/Wire
-I/Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata/src
/var/folders/64/fwfkm1k51zbd4_c5lwpsbljh0000gn/T/build8049651108713091801.tmp/StandardFirmata.cpp
-o /var/folders/64/fwfkm1k51zbd4_c5lwpsbljh0000gn/T/build8049651108713091801.tmp/StandardFirmata.cpp.o
This is actually not to do with the compiler, but the Arduino IDE. The IDE has a preprocessing step which forward-declares all the defined functions so that you don't need to worry about function placement in the file.
My strong recommendation would be to just follow the language rules and forward-declare your functions or define them before their use. Your code will be more portable and understandable for it.
No, you don't want clang to behave like gcc in this regard. In fact, use -Wall and -W (or -Wextra) in order to get gcc and clang both to give you even more warnings.
But i can find lot's of such errors in wide used examples
Sadly, getting C and C++ right is so hard that widely used examples are not good enough.
Your example includes a bug that arguably has no real effect on this program. EDIT: it appears that the IDE is clever enough to workaround language features. Refer to #TartanLlama's answer for details. Perhaps the author could make the claim that it's by design. But it's so rarely the case that clang thankfully saves you from yourself.
C89 §3.3.2.2, "Function calls" includes:
If the expression that precedes the parenthesized argument list in a
function call consists solely of an identifier, and if no declaration
is visible for this identifier, the identifier is implicitly declared
exactly as if, in the innermost block containing the function call,
the declaration
extern int identifier();
appeared
When I first learned that, I thought to myself, "OMG that's not what I wanted at all!" And, so it went with so many other folks that this "feature" was changed in C99.
Clang is per default in GNU C11 mode which is uses C99 semantics. In C99 the implicit function declaration is not allowed anymore.
you can put clang into c89 mode with clang --std=c89 or clang --std=gnu89 which should allow that behavior,
See: Are prototypes required for all functions in C89, C90 or C99?
I am building a C program with no problem on CentOS using provided Makefiles in its distro package. However I need to modify source files and I need to use iqxmlrpc and boost libraries for that purpose. I have changed Makefiles respectively but when I want to build the package I get following error:
../src/libiqxmlrpc/libiqxmlrpc/except.h:9:21: error: stdexcept: No such file or directory
../src/libiqxmlrpc/libiqxmlrpc/except.h:10:18: error: string: No such file or directory
In file included from ../src/libiqxmlrpc/libiqxmlrpc/libiqxmlrpc.h:17,
from redir.c:2617:
../src/libiqxmlrpc/libiqxmlrpc/except.h:14: error: expected '=', ',', ';', 'asm' or 'attribute' before 'iqxmlrpc'
... followed by many other errors ...
I believe above error is because iqxmlpc is written in c++ and gcc is treating it as C so I tried followings:
1) Use g++
2) Use gcc -x c++
Doing above, error changes to a lot of following in many header files:
error: expected ‘,’ or ‘...’ before ‘this’
All the lines that compiler is complaining somehow have this or delete keywords as parameter. See below:
int net_route(struct in_addr *dst, int delete);
or
extern int gad_new(struct gad_t **this)
Do you have any idea how can I fix this? Frankly, I have no idea what using 'this' or 'delete' mean as parameters. Are these only parameter names that gcc ignores the rule that we can not use keywords?
------------------------------
BTW, original programmer have used nested functions all across his code which were compiled fine using gcc. when I switch to g++, compiler complains about function-definition not being allowed in another function. Is there any way I can tell g++ to ignore this error?
Those weren't keywords in C, they are in C++.
You will have to rename those parameters before the code will compile in C++.
You may run into other porting issues related to C++'s stricter type checking before you are done.
Another option is to keep the C and C++ code in separate files, and use extern "C" in the C++ code for every function call that must cross the boundary. Since your C code extensively uses nested functions and other features not permitted in C++, this is probably your quickest approach.
this and delete are reserved keywords in C++ (not in C though) . You cannot use these as variable names when compiling with g++.
Its better to use different variable names in parameters and then compile with g++.
i have redhat with gcc 4.1.1 i have compile as "gcc test.c" and give the following error
Error : expected '=' ,',' , ';' , ásm' or '__ attribute__' before '<' token
the code in "test.c" is as follow
template <typename T> class A {
public:
T foo;
};
Compile with g++ and/or rename your file to test.cpp.
If you compile with gcc test.c then your file will be assumed as a C file. There's no templates in C.
This is C++ code, not C. You need to use g++, i.e. g++ test.c. Also, to avoid confusion, you should rename your file to end with .cpp or .cxx.
From the GCC Manual, compiling a file with the .c extension will compile your code as though it were C, not C++. The easiest solution is to compile your code with g++ instead. The g++ command sets the default language to C++ and automatically links your code against the C++ standard library. You can do both of those with gcc but you have to do it by hand. Exactly how you do that is left as an exercise. :-)
When I compile a program using just
gcc code.c
There are no messages, and an output file is generated successfully. The outputted file works. However, when I try to the same cygwin installation's gcc compiler in an IDE (I've tried Netbeans and Dev-C++), I get the following errors
main.cpp:27: error: `exit' undeclared (first use this function)
main.cpp:27: error: (Each undeclared identifier is reported only once for each function it appears in.)
main.cpp:77: error: `write' undeclared (first use this function)
main.cpp:78: error: `close' undeclared (first use this function)
I don't see what's different. Why does it not compile?
OK, the issue was that in the IDE, the file had a .cpp extension, whereas when I was compiling from a terminal, it had a .c extension. So, my new question is why does it not compile when it's treated as a c++ file. Isn't C a subset of C++?
C++ is stricter then C. Where C allows you to call a function without a prototype, C++ does not allow this.
To solve the problem, you want to add:
#include <stdlib.h>
Also, when compiling at the command line. Make sure to use the -Wall flag so you'll get important warnings:
gcc -Wall code.c
The IDE is using fussier options to the compiler. You need to include some headers:
#include <stdlib.h> // exit()
#include <unistd.h> // close(), write()
The default options allow almost anything that might be C to compile. By the looks of it, the IDE sets '-Wmissing-prototypes' as one of the compiler options.
If you compile code with a C++ compiler, you must ensure that all functions are declared before use. C is sloppier (or can be sloppier) about that - it is recommended practice to ensure all functions are declared before being defined or referenced, but it is not mandatory. In C++ it is not optional.
There is a subset of C that is also a subset of C++; there are bits of C that are not C++, and there are many bits of C++ that are not C. In particular, an arbitrary C program is not, in general, a C++ program. For example, a C program may not declare 'exit()' and yet it can both use it and still compile. A C++ program must declare 'exit()' before it can user it and compile.
You will have to use g++ for compiling .cpp files.
One possible reason may be that the IDE is unable to access the include files, the cygwin gcc compiler may be expecting it in /usr/include(not sure), and the dev-cpp may not be able to access it.