#Include problems in C

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
Scalpel

#Include problems in C

Post by Scalpel »

When I started writing my OS I put all my prototypes as well as my entire functions in my .h files. Now I've begun the work of extracting all the functions to separate files (printf.c, clear_screen.c, freeze.c and so on), but have run into some problems.

I get errors when one .c file wants to use the functions from another .c file.

I'll show you what I mean with this example.
My freeze(); function is a simple routine that writes "Kernel Frozen" to the screen, and runs a for-loop forever.

When I extracted the function to freeze.c I got errors about "implicit declaration of function printf". So I tried to #include <io.h> in the freeze.file, but then I got "multiple declaration"-errors.

Can anyone explain the proper way of using #include, or point me in the direction of a good web-page?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:#Include problems in C

Post by Pype.Clicker »

Kernigan & Ritchie ask for the developer to split their work into .C files (implementation) and .h files (module interface: structures description, function prototypes, etc.)

The usual structure is
DISPLAY.H

Code: Select all

void printchar(char);
void clearscreen();
KEYBOARD.H

Code: Select all

void waitKey();
char readKey();
CONSOLE.C

Code: Select all

#include "keyboard.h"
#include "display.h"

void readline(char *buffer) {
   char last=0;
    while (last!='\n') {
        waitKey();
         last=readKey();
         printchar(last);
         *buffer++=last;
    }
    return
}
display.c will contain the implementation of the display module. Each module consider other modules as a blackbox providing the interface described by the .h file. It shouldn't call functions that aren't in .h, it shouldn't access variables that aren't externed by the .h file, etc.

Now, when your code grow, it may happen that you have #include statements in your .h file as well, for instance because module X needs structures declared by module Y to declare its own structs.
To avoid multiple definition, you can then use the following technique:

DISPLAY.H

Code: Select all

#ifndef __DISPLAY_H
#define __DISPLAY_H
#include <global.h>
 // other includes

// local declarations
#endif
the same way, global.h will have a #ifndef __GLOBAL_H, etc.

if your C file is now carrying something like

Code: Select all

#include <global.h>
#include <display.h>
the #include global.h within display.h will be dropped silently :)
_mark

Re:#Include problems in C

Post by _mark »

A very good explaination above. In simple terms, every .H file should have multiple-include-protection.

I always use the following stratagy:

#ifndef __filename_H__
#define __filename_H__

// all code goes here.

#endif

So my stdio.h file would look something like:
#ifndef __STDIO_H__
#define __STDIO_H__

void printf(...);
void gets(...);

#endif

Note the double underscores in front and behind the H filename. This pretty much garentees I do not try to use this definition for anything else.

Also Note that the #define XXXX does not have to be defined as anything such as
#define MY_DEF some_other_thing
The fact that the symbol was defined to be nothing is sufficant for the compile to ignore the header file if it had already been included once.

_mark()
Scalpel

Re:#Include problems in C

Post by Scalpel »

Ok, thanks for your good replies. I'll try or code, but I'm sure it works :)

Btw. sub-question:

What is the difference between using <io.h> and "io.h" ?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:#Include problems in C

Post by Pype.Clicker »

"io.h" is looked up in the current directory, while <io.h> is looked in the Include path (set with -I )

maybe "io.h" falls back to the include path if it doesn't find the header file in the current directory, i never tried it ...
Whatever5k

Re:#Include problems in C

Post by Whatever5k »

maybe "io.h" falls back to the include path if it doesn't find the header file in the current directory
Yep, that's it. If the compiler cannot find the specified file in the current directory, it continues searching in the include path.
Scalpel

Re:#Include problems in C

Post by Scalpel »

Ok, I've tried to use the Inclusion guards in my .h files, but I still seem to have a problem with the linking.

Here is the short version of my kernel.c:

Code: Select all

//kernel.c

#include <io.h>
#include <cpu.h>

clear_screen();
freeze();

Code: Select all

//io.h
#ifndef __IO_H
#define __IO_H

#include <strings.h>

int global_cursor=0;

//Prototypes

void clear_screen(int);         //function exported to own file (./sources/libc/clear_screen.c)
int set_cursor (int, int);      //function exported to own file (./sources/libc/set_cursor.c)
void iprint(int, char);
void sprintf(char*, int, int);

//Functions
(..cut away functions iprint and sprintf..)

#endif

Code: Select all

#ifndef __CPU_H         //Inclusion guard
#define __CPU_H         //

#ifndef __IO_H
#include <io.h>
#endif


//Prototypes

void freeze();

#endif

Code: Select all

//freeze.c
#include <cpu.h>
#include <text_colors.h>


void freeze()
{
        sprintf ("****************", TEXT_BLACK + BACKGROUND_RED , set_cursor(1, 62));
        sprintf ("*Kernel frozen!*", TEXT_BLACK + BACKGROUND_RED , set_cursor(2, 62));
        sprintf ("****************", TEXT_BLACK + BACKGROUND_RED , set_cursor(3, 62));
        for (;;);
};
Hope thats not too much code for the forum :-[

When I compile and link this I get the error:

Code: Select all

Cerberus:~/projects/OS/HelmsDeep# make
nasm -f aout -o sources/kernel/asmkernel.o sources/kernel/asmkernel.asm
g++ -c -ffreestanding -fasm -O2 -I./includes -o sources/kernel/kernel.o sources/kernel/kernel.c
g++ -c -ffreestanding -fasm -O2 -I./includes -o sources/libc/clear_screen.o sources/libc/clear_screen.c
g++ -c -ffreestanding -fasm -O2 -I./includes -o sources/libc/set_cursor.o sources/libc/set_cursor.c
g++ -c -ffreestanding -fasm -O2 -I./includes -o sources/libc/strcmp.o sources/libc/strcmp.c
g++ -c -ffreestanding -fasm -O2 -I./includes -o sources/libc/freeze.o sources/libc/freeze.c
ld -T ./linking/kernel.lnk -o kernel.bin ./sources/kernel/asmkernel.o ./sources/kernel/kernel.o ./sources/libc/clear_screen.o 
./sources/libc/set_cursor.o ./sources/libc/strcmp.o ./sources/libc/freeze.o
./sources/libc/freeze.o: In function `convert_int_to_string(int, char *, char)':
./sources/libc/freeze.o(.text+0x0): multiple definition of `convert_int_to_string(int, char *, char)'
./sources/kernel/kernel.o(.text+0x0): first defined here
./sources/libc/freeze.o: In function `strlen(char *)':
./sources/libc/freeze.o(.text+0x8c): multiple definition of `strlen(char *)'
./sources/kernel/kernel.o(.text+0x8c): first defined here
./sources/libc/freeze.o(.data+0x0): multiple definition of `global_cursor'
./sources/kernel/kernel.o(.data+0x0): first defined here
./sources/libc/freeze.o: In function `iprint(int, char)':
./sources/libc/freeze.o(.text+0xac): multiple definition of `iprint(int, char)'
./sources/kernel/kernel.o(.text+0xac): first defined here
./sources/libc/freeze.o: In function `sprintf(char *, int, int)':
./sources/libc/freeze.o(.text+0x14c): multiple definition of `sprintf(char *, int, int)'
./sources/kernel/kernel.o(.text+0x14c): first defined here
make: *** [kernel.bin] Error 1
Does anyone see what the problem is?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:#Include problems in C

Post by Pype.Clicker »

did you by any chance put the code of some function (like strlen, for instance) in a .h file ? if you did, every .c that include the .h is going to have its own copy of the function and when you attempt to link things together, you have the same function (say, strlen) present in several modules, so the linker can't tell which one is the good one.

Once again, the good practice is:
* no function body in a .h file (except if you explicitly declared it static inline)
* no #include <file.c> from a file.h
* no #include <file.c> from a file2.c except if you can make sure file2.c is the very only one file to include <file.c>
Scalpel

Re:#Include problems in C

Post by Scalpel »

Yes, you are right. There are a few functions in my .h files. I am exporting one function after another to their own .c file now. These errors came after I moved freeze() to it's own freeze.c file.

But perhaps I should try to move all the remaining functions out of the .h-files, and then see if it works.

I thought it wouldn't be a problem because the remaining functions are placed inside the inclusion guards like this:

Code: Select all

io.h
#ifndef __IO_H
#define __IO_H

#include <strings.h>

int global_cursor=0;

//Prototypes

void clear_screen(int);        //function exported to own file (./sources/libc/clear_screen.c)
int set_cursor (int, int);      //function exported to own file (./sources/libc/set_cursor.c)
void iprint(int, char);
void sprintf(char*, int, int);

//Functions

(Functions placed HERE)

#endif
Scalpel

Re:#Include problems in C

Post by Scalpel »

Ok, that seemed to work.

It now seems that the only errors I get is from a multiple declared 'int global_cursor' variable.

The 'global_cursor' is declared in my io.h, and is used by most of the functions declared in io.h. I've tried to use 'extern int global_cursor' in the .c files, but it doesn't seem to help.

How do I then set the global variable?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:#Include problems in C

Post by Pype.Clicker »

you must replace the "int global_cursor=0" from file.h into "extern int global_cursor;" and have only one C file declaring "int global_cursor=0".

BTW, i suggest you read more about C programming language before you continue OS programming -- recommended reading : "C Language, ANSI from Brian W. Kernighan and Denis M. Ritchie" (no ISBN because i fear my french translated copy will not have the proper ISBN :) )
Scalpel

Re:#Include problems in C

Post by Scalpel »

Thanks :)

I've allready ordered my copy of Kernighans and Ritchies "The C Programming Language", and looking forward to reading it ;D
Post Reply