No GCC warning for function with declaration different from definition - c

C file definition:
#include <stdint.h>
void foo(int i)
{
if(i>0) bar();
}
H file declaration:
#ifndef FILE_H
#define FILE_H
void foo(void);
#endif FILE_H
main:
#include "file.h"
int main(void)
{
foo();
}
The file.h is not included in file.c for some abstraction reasons.
Why isn't GCC generating any warning in this particular case?

As noted in comments…
In general terms, you must include the header that declares a function both where the function is defined and where it is used. You didn't, so the compiler couldn't warn. Headers are the glue that allow the compiler to do the cross-checking necessary to ensure basic sanity in your code.
The question claims:
The file.h is not included in file.c for some abstraction reasons.
It isn't clear what those abstraction reasons are, but whatever the reasoning, it is faulty. Since the question does not (yet) specify in any more detail what the problem is, we can't help you fix the issues. However, they're spurious — you are doing something wrong.
Specifically, you must include file.h in file.c as well as inmain.c. Otherwise, you don't get the cross-checking you need — or the warning you desire. You also need a prototype for bar() in file.c — you shouldn't be calling a function without a prototype (strictly, a non-prototype declaration is sufficient, but you really want a prototype) in scope, and there's no prototype for bar() in either <stdint.h> or file.h.
I compile using GCC and options:
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes …
I don't bother to run the code until that's clean — indeed, the -Werror means I can't run the code until that's clean because the compilation fails if there is any warning or error. You can afford to go more stringent if you prefer; you shouldn't risk going much less stringent than that.
Note that both C99 and C11 require that a function is declared or defined before it is used. Only the ancient C90 standard permits calling functions that have not been pre-declared or pre-defined.

Related

Can GCC warn about undefined functions in libraries?

Consider the following test project:
test.h:
#ifndef TEST_H
#define TEST_H
void test1(int);
void test2(int);
#endif /* TEST_H */
text.c:
#include "test.h"
void test1(int x) { (void) x; }
Oops, I forgot to define test2()! I would like some kind of feedback when I do this, preferably refusal to compile although a warning at least would be nice. However GCC 10.2 (on Ubuntu 20.10) compiles it fine with no warnings:
gcc -Wall -Wextra -Wpedantic -std=c11 -o libtest.o -c test.c
I think I understand why: what if test2() is actually meant to come from another library, maybe a system library? Make it the problem of whichever program ends up linking everything into an executable! But I want to know about it before then. In this case, it's not declared in any included header file. It's not called anywhere. Can that be detected?
I've tried:
--no-undefined which resulted in gcc: error: unrecognized command-line option ‘--no-undefined’; did you mean ‘-Wno-undef’?
-Wno-undef - accepted but no warning
-z,defs - accepted but no warning
-Wimplicit-function-declaration - accepted but no warning
-Werror=missing-declarations - I know this is for the opposite situation but I was getting desperate.
This isn't possible, as no linking is performed at the stage of assembling a static library.
I'd suggest having a "test container" for your library. Set up your build system to build the test executable any time you are building the library. It could even just be a single .c file in the same directory as the library sources, but obviously not in the list of objects that are part of the library.
The test executable calls all of the functions that you wish to be entry points for the library.
Probably that is something you should be doing anyway in order to test the library's functionality before doing a release.

Is there a gcc compiler option that help capture formal and actual parameter type mismatch?

//file1.c
#include <stdio.h>
void p(int a)
{
printf("%d\n",a);
}
//file2.c
extern void p(float x); // external declaration doesn't match definition
int main(){
float b;
b=3.333f;
p(b);
}
Here the external declaration is wrong in that it is different from the actual function definition. I compile and link the two files with:
gcc -Wconversion -Wall -std=c99 file1.c file2.c
No warning is raised. Is there any gcc compiler option that can help capture this mismatch during compiling/linking?
It is not possible for a compiler to observe, while compiling file2.c, that a declaration in it does not match a declaration in file1.c, because, while compiling file2.c, the compiler has no knowledge of the contents of file1.c.
Some linkers have features that can help with this. However, this is not a common practice for linking C objects. (Perhaps it should be.)
This sort of mismatch is generally handled by using header files. The overwhelming common practice is to include declarations from a header, not to manually enter them in other source files. To do this:
Create file1.h and put void p(int a); in it.
In file1.c, insert #include "file1.h".
In file2.c, insert #include "file1.h" and remove the declaration of p.
The purpose of including file1.h in file1.c is so that the compiler will see both the declaration in file1.h and the definition in file1.c, and it will complain if they are incompatible.
Then, since file1.h is included in file2.c, we are assured the declaration seen while compiling file2.c is compatible with the definition in file1.c.
This code causes undefined behaviour because the function is called via a declaration which is not compatible with the function definition.
To help with this you can:
use -flto which will perform prototype checks at link time
use -Wmissing-declarations which will warn about file1 having a function with external linkage but no prototype
adopt a habit of never manually writing an extern function declaration in a .c file -- always include a .h file which is also included by the .c file containing the function definition (the previous option will warn about this).

How a standard library differ from user defined header file (.h) and its implementation file (.c) in C?

How a standard library like libc.a (static library) which is included using #include <stdio.h> in our main.c differ from user defined header file (cube.h) included in main.c with its implementation file (cube.c) in C ?
I mean both are header files but one's implementation is a static library (.a) and others is source file (.c) .
You would have the definition (implementation) in, say, cube.c
#include "cube.h"
int cube( int x ) {
return x * x * x;
}
Then we'll put the function declaration in another file. By convention, this is done in a header file, cube.h in this case.
int cube( int x );
We can now call the function from somewhere else, main.c for instance, by using the #include directive (which is part of the C preprocessor) .
#include "cube.h"
#include <stdio.h>
int main() {
int c = cube( 10 );
printf("%d", c);
...
}
Also if I included include guards in cube.h what would happen when I include cube.h in both main.c and cube.c . Where it will get included?
A programming language is not the same as its implementation.
A programming language is a specification (written on paper; you should read n1570, which practically is the C11 standard), it is not a software. The C standard specifies a C standard library and defines the headers to be #include-d.
(you could run your C program with a bunch of human slaves and without any computers; that would be very unethical; you could also use some interpreter like Ch and avoid any compiler or object or executable files)
How a standard library like libc.a (static library) which is included using #include <stdio.h> ... differs from a user file cube.c
The above sentence is utterly wrong (and makes no sense). libc.a does not #include -or is not included by- the <stdio.h> header (i.e. file /usr/include/stdio.h and other internal headers e.g. /usr/include/bits/stdio2.h). That inclusion happens when you compile your main.c or cube.c.
In principle, <stdio.h> might not be any file on your computer (e.g. #include <stdio.h> could trigger some magic in your compiler). In practice, the compiler is parsing /usr/include/stdio.h (and other included files) when you #include <stdio.h>.
Some standard headers (notably <setjmp.h>, <stdreturn.h>, <stdarg.h>, ....) are specified by the standard but are implemented with the help of special builtins or attributes (that is "magic" things) of the GCC compiler.
The C standard knows about translation units.
Your GCC compiler processes source files (grossly speaking, implementing translation units) and starts with a preprocessing phase (processing #include and other directives and expanding macros). And gcc runs not only the compiler proper (some cc1) but also the assembler as and the linker ld (read Levine's Linkers and Loaders book for more).
For good reasons, your header file cube.h should practically start with include guards. In your simplistic example they are probably useless (but you should get that habit).
You practically should almost always use gcc -Wall -Wextra -g (to get all warnings and debug info). Read the chapter about Invoking GCC.
You may pass also -v to gcc to understand what programs (e.g. cc1, ld, as) are actually run.
You may pass -H to gcc to understand what source files are included during preprocessing phase. You can also get the preprocessed form of cube.c as the cube.i file obtained with gcc -C -E cube.c > cube.i and later look into that cube.i file with some editor or pager.
You -or gcc- would need (in your example) to compile cube.c (the translation unit given by that file and every header files it is #include-ing) into the cube.o object file (assuming a Linux system). You would also compile main.c into main.o. At last gcc would link cube.o, main.o, some startup files (read about crt0) and the libc.so shared library (implementing the POSIX C standard library specification and a bit more) to produce an executable. Relocatable object files, shared libraries (and static libraries, if you use some) and executables use the ELF file format on Linux.
If you code a C program with several source files (and translation units) you practically should use a build automation tool like GNU make.
If I included include guards in cube.h what would happen when I include cube.h in both main.c and cube.c ?
These should be two different translation units. And you would compile them in several steps. First you compile main.c into main.o using
gcc -Wall -Wextra -g -c main.c
and the above command is producing a main.o object file (with the help of cc1 and as)
Then you compile (another translation unit) cube.c using
gcc -Wall -Wextra -g -c cube.c
hence obtaining cube.o
(notice that adding include guards in your cube.h don't change the fact that it would be read twice, once when compiling cube.c and the other time when compiling main.c)
At last you link both object files into yourprog executable using
gcc -Wall -Wextra -g cube.o main.o -o yourprog
(I invite you to try all these commands, and also to try them with gcc -v instead of gcc above).
Notice that gcc -Wall -Wextra -g cube.c main.c -o yourprog is running all the steps above (check with gcc -v). You really should write a Makefile to avoid typing all these commands (and just compile using make, or even better make -j to run compilation in parallel).
Finally you can run your executable using ./yourprog (but read about PATH), but you should learn how to use gdb and try gdb ./yourprog.
Where it cube.h will get included?
It will get included at both translation units; once when running gcc -Wall -Wextra -g -c main.c and another time when running gcc -Wall -Wextra -g -c cube.c. Notice that object files (cube.o and main.o) don't contain included headers. Their debug information (in DWARF format) retains that inclusion (e.g. the included path, not the content of the header file).
BTW, look into existing free software projects (and study some of their source code, at least for inspiration). You might look into GNU glibc or musl-libc to understand what a C standard library really contains on Linux (it is built above system calls, listed in syscalls(2), provided and implemented by the Linux kernel). For example printf would ultimately sometimes use write(2) but it is buffering (see fflush(3)).
PS. Perhaps you dream of programming languages (like Ocaml, Go, ...) knowing about modules. C is not one.
TL;DR: the most crucial difference between the C standard library and your library function is that the compiler might intimately know what the standard library functions do without seeing their definition.
First of all, there are 2 kinds of libraries:
The C standard library (and possibly other libraries that are part of the C implementation, like libgcc)
Any other libraries - which includes all those other libraries in /usr/lib, /lib, etc.., or those in your project.
The most crucial difference between a library in category 1 and a library in category 2 library is that the compiler is allowed to assume that every single identifier that you use from category 1 library behaves as if it is the standard library function and behaves as if in the standard and can use this fact to optimize things as it sees fit - this even without it actually linking against the relevant routine from the standard library, or executing it at the runtime. Look at this example:
% cat foo.c
#include <math.h>
#include <stdio.h>
int main(void) {
printf("%f\n", sqrt(4.0));
}
We compile it, and run:
% gcc foo.c -Wall -Werror
% ./a.out
2.000000
%
and correct result is printed out.
So what happens when we ask the user for the number:
% cat foo.c
#include <math.h>
#include <stdio.h>
int main(void) {
double n;
scanf("%lf\n", &n);
printf("%f\n", sqrt(n));
}
then we compile the program:
% gcc foo.c -Wall -Werror
/tmp/ccTipZ5Q.o: In function `main':
foo.c:(.text+0x3d): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
Surprise, it doesn't link. That is because sqrt is in the math library -lm and you need to link against it to get the definition. But how did it work in the first place? Because the C compiler is free to assume that any function from standard library behaves as if it was as written in the standard, so it can optimize all invocations to it out; this even when we weren't using any -O switches.
Notice that it isn't even necessary to include the header. C11 7.1.4p2 allows this:
Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.
Therefore in the following program, the compiler can still assume that the sqrt is the one from the standard library, and the behaviour here is still conforming:
% cat foo.c
int printf(const char * restrict format, ...);
double sqrt(double x);
int main(void) {
printf("%f\n", sqrt(4.0));
}
% gcc foo.c -std=c11 -pedantic -Wall -Werror
% ./a.out
2.000000
If you drop the prototype for sqrt, and compile the program,
int printf(const char * restrict format, ...);
int main(void) {
printf("%f\n", sqrt(4));
}
A conforming C99, C11 compiler must diagnose constraint violation for implicit function declaration. The program is now an invalid program, but it still compiles (the C standard allows that too). GCC still calculates sqrt(4) at compilation time. Notice that we use int here instead of double, so it wouldn't even work at runtime without proper declaration for an ordinary function because without prototype the compiler wouldn't know that the argument must be double and not the int that was passed in (without a prototype, the compiler doesn't know that the int must be converted to a double). But it still works.
% gcc foo.c -std=c11 -pedantic
foo.c: In function ‘main’:
foo.c:4:20: warning: implicit declaration of function ‘sqrt’
[-Wimplicit-function-declaration]
printf("%f\n", sqrt(4));
^~~~
foo.c:4:20: warning: incompatible implicit declaration of built-in function ‘sqrt’
foo.c:4:20: note: include ‘<math.h>’ or provide a declaration of ‘sqrt’
% ./a.out
2.000000
This is because an implicit function declaration is one with external linkage, and C standard says this (C11 7.1.3):
[...] All identifiers with external linkage in any of the following subclauses (including the future library directions) and errno are always reserved for use as identifiers with external linkage. [...]
and Appendix J.2. explicitly lists as undefined behaviour:
[...] The program declares or defines a reserved identifier, other than as allowed by 7.1.4 (7.1.3).
I.e. if the program did actually have its own sqrt then the behaviour is simply undefined, because the compiler can assume that the sqrt is the standard-conforming one.

Compiling error when -std=gnu99 and inline function is used

The following code:
#include <stdio.h>
inline int myfunc (int x) {
return x+3;
}
int main () {
printf("%d", myfunc(2));
return 0;
}
does not compile when I use the -std=gnu99 flag (I am compiling with gcc). This is the error it throws:
gcc -std=gnu99 -c main.c -o main.o
gcc -std=gnu99 main.o -o main
main.o: In function `main':
main.c:(.text+0x15): undefined reference to `myfunc'
collect2: ld returned 1 exit status
make: *** [main] Error 1
The compilation goes with no problems when -std=gnu99 is omitted. Does anyone know why is the linker complaining if -std=gnu99 is used?
In C99 you need to specify either a declaration to your inline function like
int myfunc(int);
or allow the compiler to actually inline the function by specifying -finline-functions or -O3.
Quoting the C99 standard:
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.
So the compiler is free to use the external definition of myfunc - which doesn't exist if you don't provide it, hence the linker error. Why does it prefer to choose a non existing external definition? Because you disallowed inlining by not using -finline-functions or a optimization level which contains this flag.
This is the gnu_inline hiccup. Use -std=gnu99 -fgnu89-inline.
For more information see Function Attributes (item gnu_inline).
The relevant passage:
In C, if the function is neither extern nor static, then the function is compiled as a standalone function, as well as being inlined where possible.
This is how GCC traditionally handled functions declared inline. Since ISO C99 specifies a different semantics for inline, this function attribute is provided as a transition measure and as a useful feature in its own right. This attribute is available in GCC 4.1.3 and later. It is available if either of the preprocessor macros GNUC_GNU_INLINE or GNUC_STDC_INLINE are defined. See An Inline Function is As Fast As a Macro.
You should declare 'myfunc' before define it.
For example this code can be compiled with -std=gnu99 option:
#include <stdio.h>
int myfunc(int);
inline int myfunc (int x) {
return x+3;
}
int main () {
printf("%d", myfunc(2));
return 0;
}
UPDATED
Actually, regarding to the C standard inline keyword is just a suggestion to the C compiler. But compiler can choose not to inline. So it can do its own way, therefore.
In your example you can use function declaration as I showed above - or you can add optimization flag '-O3' (tested on linux gcc) and above - in this case your source code will compiled without extra-declaration.
UPDATED
Here you can find deeper explanation: https://blogs.oracle.com/dew/entry/c99_inline_function
Apparently you need to specify that you are using and you want to adopt inline functions
-fgnu89-inline
The option -fgnu89-inline tells GCC to use the traditional GNU semantics for "inline" functions when in C99 mode. This option is
accepted and ignored by GCC versions 4.1.3 up to but not including
4.3. In GCC versions 4.3 and later it changes the behavior of GCC in C99 mode. Using this option is roughly equivalent to adding the
"gnu_inline" function attribute to all inline functions.
The option -fno-gnu89-inline explicitly tells GCC to use the C99 semantics for "inline" when in C99 or gnu99 mode (i.e., it
specifies the default behavior). This option was first supported in
GCC 4.3. This option is not supported in C89 or gnu89 mode.
The preprocessor macros __GNUC_GNU_INLINE__ and __GNUC_STDC_INLINE__ may be used to check which semantics are in
effect for "inline" functions.
Source: http://linux.die.net/man/1/gcc
So to compile your code you need at least this:
gcc source.c -std=gnu99 -fgnu89-inline

unistd.h and c99 on Linux

This simple .c file:
#include <unistd.h>
void test() {
char string[40];
gethostname(string,40);
}
... when compiled normally, works fine:
$ cc -Wall -c -o tmp.o tmp.c
$
... but when compiled in C99 mode, gives a warning:
$ cc -Wall -std=c99 -c -o tmp.o tmp.c
tmp.c: In function `test':
tmp.c:5: warning: implicit declaration of function `gethostname'
$
The resultant .o file is fine, and linking works. I'd just like to get rid of the warning. I can achieve this in a hacky way, by putting declarations in my own .h file.
What is it about C99 that means the declarations in unistd.h don't get included?
Can this be overcome, without giving up the niceness of C99?
I see the same problem for other standard libs.
You may need to define some macros in a particluar way to get the prototype for gethostname()
From man gethostname:
Feature Test Macro Requirements for
glibc (see feature_test_macros(7)):
gethostname(): _BSD_SOURCE || _XOPEN_SOURCE >= 500
sethostname(): _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
So:
#define _BSD_SOURCE
#include <unistd.h>
void test() {
char string[40];
gethostname(string,40);
}
The gory details:
If you don't specify the -std-c99 option, then features.h (which is implicitly included by unistd.h) will default to setting _BSD_SOURCE in such a way that the prototype for gethostname() gets included. However, specifying -std=c99 causes the compiler to automatically define __STRICT_ANSI__, which in turn causes features.h to not define _BSD_SOURCE, unless you force it with your own feature macro definition (as above).
gethostname( ) is not a standard C function (it's not mentioned anywhere in the C99 standard), so the symbol is correctly not defined when compiling to the standard.
If you're using the gcc toolchain, use -std=gnu99 and you'll get the behavior you want.
Alternatively, looking at <features.h>, it seems like you could use -D_GNU_SOURCE or -D_XOPEN_SOURCE=500 to get the desired behavior.
Read man gethostname. It says in the Feature Test Macro Requirements, that _BSD_SOURCE (or _XOPEN_SOURCE>500) is required to pull gethostname from unistd.h.
Next read man feature_test_macros. You will find that -std=c99 turns on __STRICT_ANSI__ which in turns off _BSD_SOURCE. This means you can't get gethostname from unistd.h unless you define _BSD_SOURCE again. I usually place _GNU_SOURCE on my command line (i.e. gcc -D_GNU_SOURCE -std=c99 file.c) for most things, which turns on _BSD_SOURCE as well.
P.S. The manual page contains an example program which can print the current ft-macros. You might compile and run it for some compiler settings.

Resources