Cross compiler swears on implicit declaration

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
mrjbom
Member
Member
Posts: 322
Joined: Sun Jul 21, 2019 7:34 am

Cross compiler swears on implicit declaration

Post by mrjbom »

Hello.

Source code and method of compilation posted here: https://github.com/mrjbom/OS

When trying to compile kmain.c, the compiler says that there is an implicit declaration.

Code: Select all

./source/kmain.c: In function ‘kmain’:
./source/kmain.c:7:5: warning: implicit declaration of function ‘initVGAMemory’ [-Wimplicit-function-declaration]
     initVGAMemory();
     ^
./source/kmain.c:8:5: warning: implicit declaration of function ‘clearVGAMemory’ [-Wimplicit-function-declaration]
     clearVGAMemory(0xFE01AC);
     ^
./source/kmain.c:9:5: warning: implicit declaration of function ‘writePixelToVGA’ [-Wimplicit-function-declaration]
     writePixelToVGA(VGA_HEIGHT - 1, VGA_WIDTH - 1, 0x00FFFFFF);
I tried to eliminate these warnings by adding to kmain.c

Code: Select all

#include "vgamemory.h"
However now I get this error:

Code: Select all

vgamem.o:(.bss+0x0): multiple definition of `VGAFRAMEBUFFER_ADDRESS'
kmain.o:(.bss+0x0): first defined here
The VGAFRAMEBUFFER_ADDRESS variable is declared in vgamemory.h

How can I solve this problem?

I hope I could explain everything. I apologize if something is unclear to you.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Cross compiler swears on implicit declaration

Post by Schol-R-LEA »

TL;DR: Move the variable definition

Code: Select all

uint32_t* VGAFRAMEBUFFER_ADDRESS = NULL;
into vgamemory.c and replace the line in vgamemory.h with

Code: Select all

extern uint32_t* VGAFRAMEBUFFER_ADDRESS;
The problem is in where you are defining the variable, as opposed to where you are declaring it; in this case, they are both on line 6 of vgamemory.h. This is a problem, since it means that, because of how the #include directive works, it means you actually defining and declaring it in both kmain.c and vgamemory.c, even though you intended it to be declared in only the header.

This is basically the same issue discussed in the wiki page Why function implementations shouldn't be put In header files, and the solution is similar: use an extern declaration in the header file (which corresponds to a funtion prototype for functions), and put the variable definition proper in one of the source files. In this case, vgamemory.c is probably the best choice for this.

It's the sort of thing which can drive even experienced C and C++ programmers to drink, as on the surface, it seems reasonable to put variable declarations in headers, until something like this crops up. It's all too easy to forget the need to make header declarations extern if you haven't had to add any in a while.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
mrjbom
Member
Member
Posts: 322
Joined: Sun Jul 21, 2019 7:34 am

Re: Cross compiler swears on implicit declaration

Post by mrjbom »

Schol-R-LEA wrote:TL;DR: Move the variable definition

Code: Select all

uint32_t* VGAFRAMEBUFFER_ADDRESS = NULL;
into vgamemory.c and replace the line in vgamemory.h with

Code: Select all

extern uint32_t* VGAFRAMEBUFFER_ADDRESS;
The problem is in where you are defining the variable...
When declaring function prototypes in .h should I do that too?
mallard
Member
Member
Posts: 280
Joined: Tue May 13, 2014 3:02 am
Location: Private, UK

Re: Cross compiler swears on implicit declaration

Post by mallard »

Schol-R-LEA wrote:It's the sort of thing which can drive even experienced C and C++ programmers to drink, as on the surface, it seems reasonable to put variable declarations in headers, until something like this crops up.
Although us C++ programmers get to "cheat" in this particular case and just declare the variable "inline" (a C++17 feature) and it works exactly as we'd like. :D
mrjbom wrote:When declaring function prototypes in .h should I do that too?
You can if you like, but it's already the default for function prototypes. The language can already tell that it's a declaration and not a definition by the lack of a function body.
Image
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Cross compiler swears on implicit declaration

Post by Schol-R-LEA »

mrjbom wrote:
Schol-R-LEA wrote:TL;DR: Move the variable definition

Code: Select all

uint32_t* VGAFRAMEBUFFER_ADDRESS = NULL;
into vgamemory.c and replace the line in vgamemory.h with

Code: Select all

extern uint32_t* VGAFRAMEBUFFER_ADDRESS;
When declaring function prototypes in .h should I do that too?
Not quite; the prototype syntax (the function signature ended with a semicolon, and without a function body) is automatically recognized as a declaration rather than a definition, so the extern keyword isn't necessary. While this is an inconsistency in the syntax, it is one which the ANSI C committee thought acceptable when they introduced prototypes of this form in 1988 (previously, prototypes only had the type and name of the function and the types of each argument, and they could even skip the arguments and type under some circumstances; indeed, IIRC, the very earliest C compilers didn't require prototypes at all for functions of one int argument and an int return type, though they were treated as mandatory by most compilers by around 1982, I think).

The only reason it becomes a problem is because it is easy to start seeing header files as their own thing, rather than as a chunk of raw text which gets inserted into the input stream by the pre-processor before the compiler even sees it. It is easy to forget about things like #include guards and extern declarations if you start forgetting that, as far as the lexical analyzer and parser are concerned, the source code and the headers #includeed into it are a single text stream.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Post Reply