I have a function declared in code.h and implemented in code.c.
it goes like:
void someFunc(const char*);
and
#include "code.h"
void someFunc(const char* str){ printf("%s\n", str); }
Now I found out I can remove the const in any one of the files (leaving it there in the other) and it compiles & runs with no errors.
I wonder what's the meaning of this?
Is one of the files the only one that matters?
It might sound like just an unimportant niche behaviour, but this fact means that a missed const can go unnoticed.
What happens if declaration and definition of a function don't agree on whether an argument is const or not?
You should get a compilation error.
What to do?
Update your compiler.
With gcc 4.2.1, I am receiving an error, if I remove const from either the header or the source file:
Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c code.c
code.c:3:6: error: conflicting types for 'someFunc'
void someFunc(const char* str){ printf("%s\n", str); }
^
./code.h:1:6: note: previous declaration is here
void someFunc(char*);
^
1 error generated.
With gcc version 4.9.2 (Debian 4.9.2-10), I am getting the same behavior.
Same behavior with gcc's 7.1.0 version, online in Wandbox:
My guess is that the behavior your are experiencing is architecture/compiler's version dependent.
In C, a diagnostic is required if function declaration and function definition are both visible to the compiler, and don't match.
If your compiler is actually a C++ compiler, the declaration and definition need not match - since they will be considered overloads. However, if both overloads are not defined, there will be linker errors (compilation units call the overload they see a declaration for, and linking fails since that function is not defined).
Other compilation units which have visibility of the declaration from the header but not of the definition will compile if arguments being passed are correct, and fail otherwise. In both C and C++.
If your code consistently builds and runs, then your compiler is not behaving in a standard way (e.g. compilation options that make it not comply in this regard). Or there is some problem with the build process (such as an object not being rebuilt if a header or source file it depends on changes - which means the executable corresponds to an older version of your source).
Related
According to C How to Program (Deitel):
Standard library functions like printf and scanf are not part of the C programming language. For example, the compiler cannot find a spelling error in printf or scanf. When the compiler compiles a printf statement, it merely provides space in the object program for a “call” to the library function. But the compiler does not know where the library functions are—the linker does. When the linker runs, it locates the library functions and inserts the proper calls to these library functions in the object program. Now the object program is complete and ready to be executed. For this reason, the linked program is called an executable. If the function name is misspelled, it is the linker which will spot the error, because it will not be able to match the name in the C program with the name of any known function in the libraries.
These statements leave me doubtful because of the existence of header file. These files are included during the preprocessing phase, before the compiling one, and, as I read, there are used by the compiler.
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
If it is as the book says, why can I declare function in header files if the compiler doesn't watch them?
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
You are right. If you made a typo in any function name, any modern compiler should complain about it. For example, gcc complains for the following code:
$ cat test.c
int main(void)
{
unknown();
return 0;
}
$ gcc -c -Wall -Wextra -std=c11 -pedantic-errors test.c
test.c: In function ‘main’:
test.c:3:5: error: implicit declaration of function ‘unknown’ [-Wimplicit-function-declaration]
unknown();
^
However, in pre C99 era of C language, any function whose declaration isn't seen by the compiler, it'll assume the function returns an int. So, if you are compiling in pre-C99 mode then a compiler isn't required to warn about it.
Fortunately, this implicit int rule was removed from the C language since C99 and a compiler is required to issue a diagnostic for it in modern C (>= C99).
But if you provide only a declaration or prototype for the function:
$ cat test.c
int unknown(void); /* function prototype */
int main(void)
{
unknown();
return 0;
}
$ gcc -c -Wall -Wextra -std=c89 -std=c11 test.c
$
(Note: I have used -c flag to just compile without linking; but if you don't use -c then compiling & linking will be done in a single step and the error would still come from the linker).
There's no issue despite the fact, you do not have definition for unknown() anywhere. This is because the compiler assumes unknown() has been defined elsewhere and only when the linker looks to resolve the symbol unknown, it'll complain if it can't find the definition for unknown().
Typically, the header file(s) only provide the necessary declarations or prototypes (I have provided a prototype for unknown directly in the file itself in the above example -- it might as well be done via a header file) and usually not the actual definition. Hence, the author is correct in that sense that the linker is the one that spots the error.
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
The compiler can see that there is no declaration in scope for the identifier designating the function. Most will emit a warning under those circumstances, and some will emit an error, or can be configured to do so.
But that's not the same thing as the compiler detecting that the function doesn't exist. It's the compiler detecting that the function name has not been declared. The compiler will exhibit the same behavior if you spell the function name correctly but do not include a prior declaration for it.
Furthermore, C90 and pre-standardization C permitted calls to functions without any prior declaration. Such calls do not conform to C99 or later, but most compilers still do accept them (usually with a warning) for compatibility purposes.
If it is as the book says, why can I declare function in header files if the compiler doesn't watch them?
The compiler does see them, and does use the declarations. Moreover, it relies on the prototype, if the declaration provides one, to perform appropriate argument and return value conversions when you call the function. Moreover, if you use functions whose argument types are altered by the default argument promotions, then your calls to such functions are non-conforming if no prototype is in scope at the point of the call. Undefined behavior results.
Recently I've learnt about implicit function declarations in C. The main idea is clear but I have some troubles with understanding of the linkage process in this case.
Consider the following code ( file a.c):
#include <stdio.h>
int main() {
double someValue = f();
printf("%f\n", someValue);
return 0;
}
If I try to compile it:
gcc -c a.c -std=c99
I see a warning about implicit declaration of function f().
If I try to compile and link:
gcc a.c -std=c99
I have an undefined reference error. So everything is fine.
Then I add another file (file b.c):
double f(double x) {
return x;
}
And invoke the next command:
gcc a.c b.c -std=c99
Surprisingly everything is linked successfully. Of course after ./a.out invocation I see a rubbish output.
So, my question is: How are programs with implicitly declared functions linked? And what happens in my example under the hood of compiler/linker?
I read a number of topics on SO like this, this and this one but still have problems.
First of all, since C99 , implicit declaration of a function is removed from the standard. compilers may support this for compilation of legacy code, but it's nothing mandatory. Quoting the standard foreword,
remove implicit function declaration
That said, as per C11, chapter §6.5.2.2
If the function is defined with a type that does not include a prototype, and the types of
the arguments after promotion are not compatible with those of the parameters after
promotion, the behavior is undefined.
So, in your case,
the function call itself is implicit declaration (which became non-standard since C99),
and due to the mismatch of the function signature [Implicit declaration of a function were assumed to have an int return type], your code invokes undefined behavior.
Just to add a bit more reference, if you try to define the function in the same compilation unit after the call, you'll get a compilation error due to the mismatch signature.
However, your function being defined in a separate compilation unit (and missing prototype declaration), compiler has no way to check the signatures. After the compilation, the linker takes the object files and due to the absence of any type-checking in the linker (and no info in object files either), happily links them. Finally, it will end up in a successful compilation and linking and UB.
Here is what is happening.
Without a declaration for f(), the compiler assumes an implicit declaration like int f(void). And then happily compiles a.c.
When compiling b.c, the compiler does not have any prior declaration for f(), so it intuits it from the definition of f(). Normally you would put some declaration of f() in a header file, and include it in both a.c and b.c. Because both the files will see the same declaration, the compiler can enforce conformance. It will complain about the entity that does not match the declaration. But in this case, there is no common prototype to refer to.
In C, the compiler does not store any information about the prototype in the object files, and the linker does not perform any checks for conformance (it can't). All it sees is a unresolved symbol f in a.c and a symbol f defined in b.c. It happily resolves the symbols, and completes the link.
Things break down at run time though, because the compiler sets up the call in a.c based on the prototype it assumed there. Which does not match what the definition in b.c looks for. f() (from b.c) will get a junk argument off the stack, and return it as double, which will be interpreted as int on return in a.c.
How are programmes with implicitly declared functions are linked? And what happens in my example under the hood of compiler/linker?
The implicit int rule has been outlawed by the C standard since C99. So it's not valid to have programs with implicit function declarations.
It's not valid since C99. Before that, if a visible prototype is not available then the compiler implicitly declares one with int return type.
Surprisingly everything is linked successfully. Of course after
./a.out invocation I see a rubbish output.
Because you didn't have prototype, compiler implicitly declares one with int type for f(). But the actual definition of f() returns a double. The two types are incompatible and this is undefined behaviour.
This is undefined even in C89/C90 in which the implicit int rule is valid because the implicit prototype is not compatible with the actual type f() returns. So this example is (with a.c and b.c) is undefined in all C standards.
It's not useful or valid anymore to have implicit function declarations. So the actual detail of how compiler/linker handles is only of historic interest. It goes back to the pre-standard times of K&R C which didn't have function prototypes and the functions return int by default. Function prototypes were added to C in C89/C90 standard. Bottom line, you must have prototypes (or define functions before use) for all functions in valid C programs.
After compiling, all type information is lost (except maybe in debug info, but the linker doesn't pay attention to that). The only thing that remains is "there is a symbol called "f" at address 0xdeadbeef".
The point of headers is to tell C about the type of the symbol, including, for functions, what arguments it takes and what it returns. If you mismatch the real ones with the ones you declare (either explicitly or implicitly), you get undefined behavior.
I was reviewing a particular code snippet in which function is declared as
int fn_xyz()
but while referencing the function in another .c file, it is defined as :
extern void fn_xyz()
while fn_xyz is called, there is no check for the return values ; GCC-4.7.0 never warned on the above mismatch ; is this expected ?
Each source file (technically, each translation unit) is compiled completely independently of the others. So the compiler never knows that you've declared the same symbol in multiple places. At link time, all type information has been removed, so the linker can't complain either.
This is precisely why you should declare functions in a header that all source files then include. That way, type mismatches will trigger a compiler warning/error.
Since the linking stage happens after compilation (and the compiler doesn't know or care where you link to; like linking to a shared libary), it makes sense that such a test would not be expected of a compiler.
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.
I have gone through some posts related to this topic but was not able to sort out my doubt completely. This might be a very naive question.
I have a header file inline.h and two translation units main.cpp and tran.cpp.
Details of code are as below
inline.h
#ifndef __HEADER__
#include <stdio.h>
extern inline int func1(void)
{ return 5; }
static inline int func2(void)
{ return 6; }
inline int func3(void)
{ return 7; }
#endif
main.c
#define <stdio.h>
#include <inline.h>
int main(int argc, char *argv[])
{
printf("%d\n",func1());
printf("%d\n",func2());
printf("%d\n",func3());
return 0;
}
tran.cpp
//(note that the functions are not inline here)
#include <stdio.h>
int func1(void)
{ return 500; }
int func2(void)
{ return 600; }
int func3(void)
{ return 700; }
The above code compiles in g++, but does not compile in gcc (even if you make changes related to gcc like changing the code to .c, not using any C++ header files, etc.). The error displayed is "duplicate definition of inline function - func3".
Can you clarify why this difference is present across compilers?
Also, when you run the program (g++ compiled) by creating two separate compilation units (main.o and tran.o) and create an executable a.out, the output obtained is:
500
6
700
Why does the compiler pick up the definition of the function which is not inline. Actually, since #include is used to "add" the inline definition I had expected 5,6,7 as the output. My understanding was during compilation since the inline definition is found, the function call would be "replaced" by inline function definition.
Can you please tell me in detailed steps the process of compilation and linking which would lead us to 500,6,700 output. I can only understand the output 6.
This answer is divided into the following sections:
How to reproduce the duplicate definition of inline function - func3 problem and why.
Why defintion of func3 is a duplicate instead of func1.
Why it compiles using g++
How to produce the duplicate definition of inline function - func3 problem
The problem can be successfully reproduced by
Rename tran.cpp to tran.c
Compile with gcc -o main main.c tran.c
#K71993 is actually compiling using the old gnu89 inline semantics, which is different from C99. The reason for renaming tran.cpp to tran.c is to tell the gcc driver to treat it as C source instead of C++ source.
Why definition of func3 is a duplicate instead of func1.
GNU 89 inline semantics
The following text is quoted from GCC Document: An Inline Function is As Fast As a Macro explains why func3 is a duplicate definition instead of func1, since func3 (instead of func1) is an externally visible symbol (in GNU89 inline semantics)
When an inline function is not static, then the compiler must assume that there may be calls from other source files; since a global symbol can be defined only once in any program, the function must not be defined in the other source files, so the calls therein cannot be integrated. Therefore, a non-static inline function is always compiled on its own in the usual fashion.
If you specify both inline and extern in the function definition, then the definition is used only for inlining. In no case is the function compiled on its own, not even if you refer to its address explicitly. Such an address becomes an external reference, as if you had only declared the function, and had not defined it.
C99 inline semantics
If compiled with C99 standard, i.e., gcc -o main main.c tran.c -std=c99, the linker will complain that definition of func1 is a duplicate due to the reason that extern inline in C99 is a external definition as mentioned in other posts and comments.
Please also refer to this execellent answer about semantic differents between GNU89 inline and C99 inline.
Why it compiles using g++.
When compiled with g++, the source program are considered as C++ source. Since func1, func2 and func3 are defined in multiple translation units and their definitions are different, the One Defintion Rule of C++ is violated. Since the compiler is not required to generate dignostic message when definitions spans multiple translation units, the behavior is undefined.
Maybe you should post the actual code. The snippets you show don't compile:
inline.h has extern inline int func1(void) That doesn't make any sense.
main.h has #define <stdio.h> I think you meant include instead.
Once I fixed those and compiled with gcc, it compiled fine and I got the following output
5
6
7
When I compile with g++, I get this output:
5
6
700
That happens because func3() is not static in inline.h
The compiling error is because there is a duplicate definition of func1();
Because func1() is defined using extern inline, it will produce a external definition.
However, there is also an external definition in tran.c, which cause multiple definition error.
However, func2() and func3() do not produce an external definition, hence no redefinition error.
You might want to look at here http://www.greenend.org.uk/rjk/2003/03/inline.html.
Also, take a note that c++ and c treats inline functions differently, and even in c, different standards (c89 vs. c99) treats inline functions differently.
Your code is invalid from the C++ point of view, since it blatantly violates the One Definition Rule. The only reason you managed to compile it by C++ compiler is the loose error checking in your C++ compiler (it happens to be one of those parts of ODR where "no diagnostic is required").
Your code is not valid C, because it provides duplicate external definition of function func1. Note that it is func1, not func3 that is problematic from the C point of view. There's nothing formally wrong with your func3. Your func2 is also OK, as long as the two definitions never "meet" each other in the same translation unit.
One possible reason you might be getting a different diagnostic report from your compiler is that your C compiler might be supporting inline functions in some non-standard compiler-specific way (either a pre-C99 compiler or a modern compiler run in non-standard "legacy" mode).
Frankly, I find it hard to believe you are getting an error report about func3 from any compiler, assuming the code you posted accurately represents what you are trying to compile. Most likely what you posted is not the real code.
The compile error you see is actually a linker error.
gcc and g++ are treating static inline a little differently. inline was first part of C++ and then made into an extension to many C compilers, before being added to standard C. The standard semantics could be different, but it could just be the implementations that are different.
It could also have something to do with some crazy stuff that happens with C++ code that gets rid of duplicate template stuff catching other duplicate stuff as well.
basically Inline is a late entry to GCC ( I mean c compiler).
"[ . . . ] An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition."
— ISO 9899:1999(E), the C99 standard, section 6.7.4