c header-guards are ignored? - c

Why does gcc ignore these header guards in this simple test program?
The header file is:
#ifndef MYHEADER_H
#define MYHEADER_H
#warning "header declared"
int some_int=0;
#endif
And the two .c files are:
main.c:
#include "header.h"
int main ()
{
return some_int;
}
source.c:
#include "header.h"
int get_int()
{
return some_int;
}
When compiling with:
gcc -o out main.c source.c
I get the following output:
In file included from main.c:1:
header.h:4:2: warning: #warning "header declared" [-Wcpp]
4 | #warning "header declared"
| ^~~~~~~
In file included from source.c:1:
header.h:4:2: warning: #warning "header declared" [-Wcpp]
4 | #warning "header declared"
| ^~~~~~~
/usr/bin/ld: /tmp/ccmAbN1J.o:(.bss+0x0): multiple definition of `some_int'; /tmp/ccEd5PwN.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
As expected, the warning shows up, when the compiler includes the header file for the first time. But why wont the header guards stop the second inclusion?
The gcc version is:
gcc version 9.2.1 20200130 (Arch Linux 9.2.1+20200130-2)

Header guards guard against multiple inclusion in a single translation unit (usually a .c file and everything it includes, directly or indirectly).
You have two translation units, main.c and source.c, and they're compiled independently (even if you use a single command line line gcc main.c source.c). That's why you're getting an error message from the linker, not from the compiler.
If you want to define an object, you should do it in a .c file and declare it as extern in the corresponding .h file. The .c file defining the object is compiled just once, and multiple other .c files can see the declaration in the .h file.

It's not ignoring them. You have two separate compilation units there and each one needs header.h. Header guards are intended to prevent a single compilation unit from including the same header twice. For example. If main.c included header.h' directly, but also includedfoo.hwhich also includedheader.h, when all the includes are expanded the header guard ensures thatheader.h`'s contents only appear once.

There are 2 compilation units : 1 for main.c and 1 for source.c. These are compiled separately (and completely independently) by the compiler, resulting in 2 object files (eg. main.o resp. source.o). Each of these prints the warning :
In file included from main.c:1:
header.h:4:2: warning: #warning "header declared" [-Wcpp]
4 | #warning "header declared"
| ^~~~~~~
These object files are then linked into an executable out by the linker.
But the linker discovers that both object files define the same symbol some_int, and thus fails to generate the executable, resulting in :
/usr/bin/ld: /tmp/ccmAbN1J.o:(.bss+0x0): multiple definition of `some_int'; /tmp/ccEd5PwN.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status

Related

undefined reference to `CreateRGBABitmapImageReference' [duplicate]

I would like to compile this.
program.c
#include <libavcodec/avcodec.h>
int main(){
int i = avpicture_get_size(AV_PIX_FMT_RGB24,300,300);
}
Running this
gcc -I$HOME/ffmpeg/include program.c
gives error
/tmp/ccxMLBme.o: In function `main':
program.c:(.text+0x18): undefined reference to `avpicture_get_size'
collect2: ld returned 1 exit status
However, avpicture_get_size is defined. Why is this happening?
However, avpicture_get_size is defined.
No, as the header (<libavcodec/avcodec.h>) just declares it.
The definition is in the library itself.
So you might like to add the linker option to link libavcodec when invoking gcc:
-lavcodec
Please also note that libraries need to be specified on the command line after the files needing them:
gcc -I$HOME/ffmpeg/include program.c -lavcodec
Not like this:
gcc -lavcodec -I$HOME/ffmpeg/include program.c
Referring to Wyzard's comment, the complete command might look like this:
gcc -I$HOME/ffmpeg/include program.c -L$HOME/ffmpeg/lib -lavcodec
For libraries not stored in the linkers standard location the option -L specifies an additional search path to lookup libraries specified using the -l option, that is libavcodec.x.y.z in this case.
For a detailed reference on GCC's linker option, please read here.
Are you mixing C and C++? One issue that can occur is that the declarations in the .h file for a .c file need to be surrounded by:
#if defined(__cplusplus)
extern "C" { // Make sure we have C-declarations in C++ programs
#endif
and:
#if defined(__cplusplus)
}
#endif
Note: if unable / unwilling to modify the .h file(s) in question, you can surround their inclusion with extern "C":
extern "C" {
#include <abc.h>
} //extern

Export .h defines in .S file

I have to include some of the macros from .h in .S file. .h includes c declarations as well. Hence I took the defines out using
gcc -E -dM header.h > generated_header.h
generated_header.h has all predefined macros and standard symbols also.
Now gcc -Iinclude/ asm.S -o asm.o gives number of following warnings
warning: "__GCC_ATOMIC_LLONG_LOCK_FREE" redefined
warning: "__GCC_ATOMIC_SHORT_LOCK_FREE" redefined
warning: "__STDC__" redefined etc...
This is because we are redefining same macros again by including generated_header.h in asm.S
I checked all the preprocessor options for extracting only local defines. But nothing helped. Is there any other way to solve this. Is there any other way to make asm.S to be aware of those macros?.

multiple definitions even though I'm using extern and include guards

Here's my header file.
#ifndef P6_H
#define P6_H
#include <stdio.h>
void FoundationC();
void StructureC();
void PlumbingC();
void ElectricC();
void HVACC();
void SheatingC();
extern int DAYS;
#endif
I'm using a makefile to do all compilation. It's able compile the individual .o files file but when it tries turn those into a single executable it says that there multiple definitions of the variable DAYS even though that is extern and declared and initialized in each individually. I got this to work before but can't figure out why it's not working now.
Oh and here's my makefile code
all:
gcc -c P6.c
gcc -c foundations.c
gcc -c structure.c
gcc -c plumbing.c
gcc -c electric.c
gcc -c hvac.c
gcc -c sheating.c
gcc P6.h P6.o foundations.o structure.o plumbing.o electric.o hvac.o sheating.o -o P6
I realize P6.h probably doesn't have to be include in the command but the include guards should make it not matter no?
Also I'm sorry if this question is a dupe but I did previously look for answers and this issue is driving me crazy on a personal level despite the fact that's it's for school.
Here are the errors I get.
gcc -c P6.c
gcc -c foundations.c
gcc -c structure.c
gcc -c plumbing.c
gcc -c electric.c
gcc -c hvac.c
gcc -c sheating.c
gcc P6.h P6.o foundations.o structure.o plumbing.o electric.o hvac.o sheating.o -o P6
structure.o:(.data+0x0): multiple definition of `DAYS'
foundations.o:(.data+0x0): first defined here
plumbing.o:(.data+0x0): multiple definition of `DAYS'
foundations.o:(.data+0x0): first defined here
electric.o:(.data+0x0): multiple definition of `DAYS'
foundations.o:(.data+0x0): first defined here
hvac.o:(.data+0x0): multiple definition of `DAYS'
foundations.o:(.data+0x0): first defined here
sheating.o:(.data+0x0): multiple definition of `DAYS'
foundations.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [all] Error 1
To help you understand, the following is an extension of #FUZxxl's answer, which is correct. If you have the following in your compilation unit (a compilation unit is the .c source file plus all included .h files):
extern int DAYS;
...
int DAYS = 1;
then the second declaration of DAYS overrides the first declaration which stated it is an extern. So, the variable is now no longer an extern and if you do this in more than one source file you now consequently have multiple definitions and the linker complains.
If you must initialize DAYS, then you can do that in one place, preferably in the main file.
initialized in each individually.
There's your mistake. What do you think is supposed to happen if you initialize the same variable in different translation units? What do you think happens if these use different values?
You can only define a variable once in your program, multiple declarations are fine though. From all but one translation unit, remove the definition of DAYS to fix this problem.
First of all,remove P6.h from the last command in the makefile.-o option in gcc is used for compiling and linking multiple source files.So,this doesn't make any sense.
Secondly define DAYS as "int DAYS" in a .c file,you could declare it as extern in the corresponding .h file and include this .h file in all other source .c files.This will resolve this issue of multiple definitions.
Example:Define days as "int DAYS" in A.c and you declare it as "extern int DAYS" in A.h.Now,you could include this A.h in rest other source files like B.c , C.c ,D.c and so on.

Compiling with gcc including .h files?

I'm trying to compile some AES implementation code from http://www.efgh.com/software/rijndael.htm, I got a txt file and splitted it up so I got 3 files:
encrypt.c
decrypt.c
rijndael.h
Having all this 3 files in the same folder, I try to compile any of encrypt.c or decrypt.c files but it throws some errors about undefined functions which actually are in rijndael.h
I'm performing compilation this way:
gcc -o encrypt encrypt.c or gcc -o decrypt decrypt.c
And I get:
/tmp/cch6JvXT.o: In function main:
encrypt.c:(.text+0x127): undefined reference to rijndaelSetupEncrypt
encrypt.c:(.text+0x1c6): undefined reference to rijndaelEncrypt
collect2: error: ld returned 1 exit status
But rijndaelSetupEncrypt and rijndaelEncrypt are in the rijndael.h file
There is a difference between an "undeclared function" error and an "undefined function" error. The first one is given when it can not find the prototype (meaning only the function header) of a function you've used, prototypes being usually put in the .h files and included in your .c files. The second error appears when it finds the prototype but not the definition of the function. The definition of a function (meaning the entire body of a function) can be fount either in a library or in another .c file that you should add to your compile command.
For "undefined function" error you could try
gcc -o enc_dec encrypt.c decrypt.c
if the function it cannot find is in one of the two .c files you've mentioned.
If it's not, you might have forgotten to link a library.
Later edit:
With the rijndael.c file:
gcc -o decrypt rijndael.c decrypt.c
gcc -o encrypt rijndael.c encrypt.c
It doesn't matter if rijndael.h hasn't got a main function. I suppose it has definitions for some of the functions used in decrypt.c and encrypt.c
Actually in your example, you should have 4 files, encrypt.c decrypt.c rijndael.c and rijndael.h
So you have to compile rijndael.c and encrypt.c or same with decrypt together. .h files will be automatically used during compilation of c file which included the .h (header) file.

error: unknown type name ‘bool’

I downloaded the source code and wanted to compile the file of scanner. It produces this error:
[meepo#localhost cs143-pp1]$ gcc -o lex.yy.o lex.yy.c -ll
In file included from scanner.l:15:0:
scanner.h:59:5: error: unknown type name ‘bool’
In file included from scanner.l:16:0:
utility.h:64:38: error: unknown type name ‘bool’
utility.h:74:1: error: unknown type name ‘bool’
In file included from scanner.l:17:0:
errors.h:16:18: fatal error: string: No such file or directory
compilation terminated.
And I tried to use different complier to compile it, but it appeared different errors.
[meepo#localhost cs143-pp1]$ g++ -o scan lex.yy.c -ll
/usr/bin/ld: cannot find -ll
collect2: ld returned 1 exit status
My os is 3.0-ARCH, I don't know why this happened. How do I fix the error?
C90 does not support the boolean data type.
C99 does include it with this include:
#include <stdbool.h>
C99 does, if you have
#include <stdbool.h>
If the compiler does not support C99, you can define it yourself:
// file : myboolean.h
#ifndef MYBOOLEAN_H
#define MYBOOLEAN_H
#define false 0
#define true 1
typedef int bool; // or #define bool int
#endif
(but note that this definition changes ABI for bool type so linking against external libraries which were compiled with properly defined bool may cause hard-to-diagnose runtime errors).
Just add the following:
#define __USE_C99_MATH
#include <stdbool.h>
Somewhere in your code there is a line #include <string>. This by itself tells you that the program is written in C++. So using g++ is better than gcc.
For the missing library: you should look around in the file system if you can find a file called libl.so. Use the locate command, try /usr/lib, /usr/local/lib, /opt/flex/lib, or use the brute-force find / | grep /libl.
Once you have found the file, you have to add the directory to the compiler command line, for example:
g++ -o scan lex.yy.c -L/opt/flex/lib -ll

Resources