c code: how to detect duplicate function declarations - c

Is there a FLAG setting in makefile to detect duplicate function declarations?
Duplicate function declarations in a header file are found, but compiler doesn't report it even FLAG is set as "warning as error".
Does this bring any implicit problem?

You're trying to solve a problem that doesn't exist. There is generally no problem with duplicated function declarations, so there is no reason for a compiler to diagnose them.
A C compiler will typically diagnose situations, in the same compilation unit, where a function is declared in more than one way (e.g. two declarations of the same function with different return type or argument types).
Duplicate function definitions (a particular type of function declaration - which implements the function) are a problem. Practically, a compiler will give warnings or errors when multiple definitions of a function occur in a compilation unit. A linker will also report cases where a function is defined in more than one compilation unit - the exceptions being functions that are either inline or static (local to its compilation unit).

Duplicate function declarations are NOT a problem so why compiler need to report about it as a problem?
This scenario is really common:
source 1:
//definition
int func(void) {
...
}
source 2:
//declaration
extern int func(void);
source 3:
extern int func(void); //duplicate with source 2

I don't like using extern, especially for functions. Declare your function in a single header file and then include that header file in the other compilation units. If the function is only used by a single compilation unit, declare it as static with the .c file itself.

Related

How does extern inline declaration cause code generation?

I'm quoting these lines from this link:
Is "inline" without "static" or "extern" ever useful in C99?
To make inline work in c99 we need to do the following:
non-extern "inline" definition goes in the header (but does not necessarily result in any code generation at all), while the "extern inline" declaration goes in the .c file and actually causes the code to be generated.
The above behaviour has been questioned about but there is no answer I could find.
It just seems the C designer were high at the time. How does the above
rule work? In every other C style coding definition goes in header and declaration goes in source file. But here it's backward and a declaration causes code generation?
You're saying that "function definitions should go to translation units"... yes, but an inline function is such that it is supposed to be inlinable in another translation unit. And the C compilers commonly do not look for code to inline from other translation units, but they just compile separate translation units into separate object files and only the linker would see the program in its entirety.
Back in times the solution for this would be to define a function in a header file with static (note it is a definition in a header file!), and hope that the compiler would be smart enough to inline the function. But a stupid compiler would generate a separate static function in each translation unit, and not inline anything, leading to both bad performance and wasted memory.
Now with inline and extern inline it means that a function defined as inline foo is supposed to be the same function throughout the program - you can take the function pointer of it in any translation unit and you will get the same function pointer.
Anywhere you see inline void foo(int bar) { ... } it is equally a function definition. But only in one translation unit in the entire program would there be extern inline void foo(int bar); that would cause the function with external linkage to appear in that file. This has a nice property in that it makes legacy tool chains (linkers etc) be able to completely ignore the inline keyword behaviour, they just see that there is one symbol foo for a function in that one object file.
Finally, you're not required to have the same function definition as the externally defined one - it can be a different one - just do not include the inline function definition from the header but define a completely different one, for example
inline int foo(void) {
puts("Hello from an inlined function");
}
extern inline int foo(void) {
puts("Hello from an external function using a completely different algorithm"
" here that results in more code bloat but offsets the fact that the"
" function call to this definition was not inlined");
}
But it is nice that the C allows you to have the same definition without repeating yourself!
It might be clearer to say the extern declaration triggers generation of an external definition of the function rather than that it causes code to be generated.
As long as all of the declarations of a function in a translation unit are inline without extern, the compiler just provides inline implementations, per C 2018 6.7.4 7:
… If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function,…
So, when you add an extern declaration, the condition in that rule is no longer satisfied—it is no longer true that there are only inline declarations without extern. That cues the compiler to include an external non-inline implementation in the code it generates.

if global variable have default external linkage then why can't we access it directly in another file?

I have gone through following questions:
Global variable in C are static or not?
Are the global variables extern by default or it is equivalent to declaring variable with extern in global?
Above links describe that if we define global variable in one file and haven't specified extern keyword they will be accessible in another source file because of translation unit.
Now I have file1.c in that have defined following global variable and function:
int testVariable;
void testFunction()
{
printf ("Value of testVariable %d \n", testVariable);
}
In file2.c have following code
void main()
{
testVariable = 40;
testFunction();
}
Now I am getting error: 'testVariable' undeclared (first use in this function) -- why?
Note: both files are used in same program using makefile.
As per my understanding both function and global variable have default external linkage. So function we can use directly by it's name in another file but variable can't why?
Can any one have idea?
EDIT:
From the below answer i get idea that like in case of function old compiler will guess and add an implicit declaration but in case of variable it can't. Also C99 removed implicit declaration but still I am getting warning in C99 mode like:
warning: implicit declaration of function ‘testFunction’.
Now have gone through below link:
implicit int and implicit declaration of functions with gcc compiler
It said that compiler take it as diagnostic purpose and not give error. So compiler can process forward.
But why in case of variable it can't process further? Even in case of function if compiler proceed and if actual definition not there then at linking time it will fail. So what's benefit to move forward??
There are two things in play here: The first is that there is a difference between a definition and a declaration. The other thing is the concept of translation units.
A definition is what defines the variable, it's the actual place the variable exists, where the compiler reserves space for the variable.
A declaration is needed for the compiler to know that a symbol exists somewhere in the program. Without a declaration the compiler will not know that a symbol exists.
A translation unit is basically and very simplified the source file plus all its included header files. An object file is a single translation unit, and the linker takes all translation units to create the final program.
Now, a program can only have a single definition, for example a global variable may only exist in a single translation unit, or you will get multiple definition errors when linking. A declaration on the other hand can exist in any number of translation units, the compiler will use it to tell the linker that the translation references a definition in another (unknown at time of compilation) translation unit.
So what happens here is that you have a definition and a declaration in file1.c. This source file is used as input for one translation unit and the compiler generates a single object file for it, say file1.o. In the other source file, file2.c, there is no definition nor any declaration of the global variable testVariable, so the compiler doesn't know it exists and will give you an error for it. You need to declare it, for example by doing
extern int testVariable; // This is a declaration of the variable
It's a little more complicated for the function, because in older versions of the C standard one didn't have to declare functions being used, the compiler would guess and add an implicit declaration. If the definition and the implicit declaration doesn't match it will lead to undefined behavior, which is why implicit function declarations was removed in the C99 standard. So you should really declare the function too:
void testFunction(void); // Declare a function prototype
Note that the extern keyword is not needed here, because the compiler can automatically tell that it's a function prototype declaration.
The complete file2.c should then look like
extern int testVariable; // This is a declaration of the variable
void testFunction(void); // Declare a function prototype
void main()
{
testVariable = 40;
testFunction();
}
When compiler copes with file2.c it knows nothing about existence of testVariable and about its type. And as result it can't generate code to interact with such object. And purpose of line like
extern int testVariable;
is to let compiler to know that somewhere such object exists and has type of int.
With functions we have no such problem because of next rule - if function is not defined - compiler assumes that it is defined somewhere like
int testFunction() { ... }
So you can pass any number of any arguments to it and try to obtain int return value. But if real function signature differs - you'll get an undefined behafiour at runtime. Because of this weakness such approach is considered as bad practice, and you should declare proper function prototype before any call to that func.

Function definition and extern declaration are different ; but GCC does not even warn and passes the compilation

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.

extern function prototype and static definition

I am working on getting FreeGLUT to build on OSX and am running into many instances of the same problem. Many of the functions exist only in the .c files.
Here's an example
extern void fghRestoreState( void );
static void fghRestoreState( void ){...}
I have a limited understanding of C, but the compiler errors seem to make sense:
src/Common/freeglut_gamemode.c:252: error: static declaration of ‘fghRestoreState’ follows non-static declaration
src/Common/freeglut_gamemode.c:43: error: previous declaration of ‘fghRestoreState’ was here
My question is, is there any reason they set it up this way? Would it compile on other platforms correctly?
The keyword extern in front of the function means external linkage.
It enables you to use functions defined in other Translation units to your own source file.
In Simple words, It enables you to use the fghRestoreState() in another file which does not include the declaration of it.
Whereas, the keyword static implies an Internal Linkage, that is the function should be visible only in the file in which is it defined and declared.
In Simple words, it tells the compiler I will be using this function only in this source file so hide it from all the other files in my project.
The error since as stated above there is a conflict in using the two keywords together.
You cannot tell the compiler to enable all files to see this function(using extern) & again tell it, hide it from all other files(using static).
So choose the keyword as per your usage of the function.

Compiler/Linking Error: Freedup

I've been trying to compile a program for hardlinking duplicate files called freedup. I did try to email the author/maintainer of the program, but it's been a long time and I haven't heard anything back from him.
I'm trying to compile the program from a cygwin environment using the latest stable versions of gcc (3.4.4-999) and make (3.81-2). I've tried deleting all the object files and running make, but I always get the following error:
freedup.o: In function 'main':
/home/[user]/freedup-1.5/freedup.c:1791: undefined reference to '_hashed'
collect2: ld returned 1 exit status
make: * * * [freedup] Error 1
I did take a look at the source code and saw that the "hashed" function is an inline function (which I didn't think had to be declared outside of the source file... but that's just what I gathered from some preliminary googling).
If anyone would be kind enough to try compiling this program in a windows environment and has any luck, I'd really appreciate it. Thanks
The direct link for the source files is: http://freedup.org/freedup-1.5-3-src.tgz
I'm not impressed by code that uses '#include <linux/stat.h>' instead of '#include <sys/stat.h>'. I'm also unimpressed by code where the version.h file contains:
-e #define VERSION "1.5-3"
(That file is generated by a command - 'echo -e '#define...' > version.h'. Ugh!)
If you change the function from:
inline int hashed(const char*s)
{
int returnval=atoi(s);
if(returnval>2) returnval=2;
if(returnval<0) returnval=0;
return returnval;
}
to:
static
inline int hashed(const char*s)
{
int returnval=atoi(s);
if(returnval>2) returnval=2;
if(returnval<0) returnval=0;
return returnval;
}
(and fix the other problems alluded to above), then it compiles on MacOS X 10.6.2 with GCC
"i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) (dot 1)".
The test code fails at random points since it assumes the touch in /bin/touch (it is /usr/bin/touch on MacOS X). There are also many warnings about 'type qualifiers ignored on function return type' because 'auto.h' defines 4 functions as returning 'const int' (for various guises of 'int'), and also in function pointers in a structure in the same header.
I guess this comes down to insufficient experience on the part of the authors - or insufficient platforms tested. The version.h command does not need to use a tab (I believe the '-e' is to expand the '\t' notation in the command line - the Makefile should be fixed to omit the '-e' and replace the '\t' with a simple blank.
The behaviour of 'inline' in standard C99 is interesting:
6.7.4 Function specifiers
Syntax
function-specifier:
inline
Constraints
Function specifiers shall be used only in the declaration of an identifier for a function.
An inline definition of a function with external linkage shall not contain a definition of a
modifiable object with static storage duration, and shall not contain a reference to an
identifier with internal linkage.
In a hosted environment, the inline function specifier shall not appear in a declaration
of main.
Semantics
A function declared with an inline function specifier is an inline function. The
function specifier may appear more than once; the behavior is the same as if it appeared
only once. Making a function an inline function suggests that calls to the function be as
fast as possible.118) The extent to which such suggestions are effective is
implementation-defined.119)
Any function with internal linkage can be an inline function. For a function with external
linkage, the following restrictions apply: If a function is declared with an inline
function specifier, then it shall also be defined in the same translation unit. If all of the
file scope declarations for a function in a translation unit include the inline function
specifier without extern, then the definition in that translation unit is an inline
definition. 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.120)
118) By using, for example, an alternative to the usual function call mechanism, such as ‘‘inline
substitution’’. Inline substitution is not textual substitution, nor does it create a new function.
Therefore, for example, the expansion of a macro used within the body of the function uses the
definition it had at the point the function body appears, and not where the function is called; and
identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a
single address, regardless of the number of inline definitions that occur in addition to the external
definition.
119) For example, an implementation might never perform inline substitution, or might only perform inline
substitutions to calls in the scope of an inline declaration.
120) Since an inline definition is distinct from the corresponding external definition and from any other
corresponding inline definitions in other translation units, all corresponding objects with static storage
duration are also distinct in each of the definitions.
Jonathan Leffler provides the answer for freedup 1.5.3: add 'static' or remove 'inline' on the hashed function. (You should probably accept that answer.)
freedup 1.6-* doesn't compile on Cygwin at all:
socket.c:20:26: fatal error: net/ethernet.h: No such file or directory
This file doesn't exist in Cygwin.

Resources