You are not logged in.

#1 2011-12-07 17:35:42

GalacticArachnid
Member
Registered: 2009-01-02
Posts: 155
Website

Noob C question: multiple source files and that

I seem to have lost this knowlage (or maybe never had it)..


..But, before you hit me up with the "let me google that for you" link..

files structure:

 ./src/global.h                --some global define etc
 ./src/main_proj.h          --not actually used yet
 ./src/main_proj.c          --the main() call that ties in all other utility functions

 ./src/lib/a.h                    --defs and struct typdefs
 ./src/lib/a.c                    --various utility functions

  plus about 5 more .c&.h pairs in ./lib

main_proj.c

/*
 * .include
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// ( ... )
#include <math.h>

#include "global.h"
#include "lib/a.h"
#include "lib/b.h"
//( ... )

/*
 * .text
 */
int main( int argc, char *argv[] )
{
 // (   ....   )

the files in ./src/lib/   do not have any include statements. Previously though they did, such as:

./src/lib/a.c

#include "a.h"

// (  ... )
void some_code( void ){}

in either case I can compile the code just fine, /but/ when i try to build ( -o ) I get complaints from ld about undefined references to the function names (that exist in the various lib/*.c files, and are prototyped in their relative .h files.

---
Is my question clear, if so, what am I doing wrong?

compile with:

src$ gcc -Wall -c main_proj.c

build with:

src$ gcc lib/*.c main_proj.c -o main_proj

system complains a lot about things like uint32_t being unknown (ive included stdint.h in main_proj.c), #defines from global.h nor being seen in the later lib/*.c files..

Offline

#2 2011-12-07 20:16:00

/dev/zero
Member
From: Melbourne, Australia
Registered: 2011-10-20
Posts: 1,247

Re: Noob C question: multiple source files and that

What's in the header files a.h and b.h? Also, it would help your debugging if you reduced it to the bare minimum example, make that work, and then start bringing in other stuff. Eg, why do you have "#include <math.h>"? None of your example code requires it.

Offline

#3 2011-12-07 20:32:14

bjornoslav
Member
Registered: 2011-11-01
Posts: 137

Re: Noob C question: multiple source files and that

Try instead of #include "lib/a.h" to give the path with a leading ./, like #include "./lib/a.h". Do that for all the header files of yours you included. Did that work?


asus ux303la, core i5@1.6ghz, 8 gb ram, 500gb hdd, hd4400 gpu, crux x64 with openbox

Offline

#4 2011-12-08 03:17:08

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: Noob C question: multiple source files and that

Most likely, you need to build with the math lib.

$ gcc -Wall lib/*.c main_proj.c -lm -o main_proj

also, you don't need to do this

$ gcc -c main_proj.c

if you do the above.

Offline

#5 2011-12-08 12:16:33

GalacticArachnid
Member
Registered: 2009-01-02
Posts: 155
Website

Re: Noob C question: multiple source files and that

Got it working by having each header refer to any other header that it needs data from.. but this seems very very unclean and I would have though that anything linked in at the top of my code would be visible to functions linked in afterwards.


global.h

#ifndef __GLOBAL_
#define __GLOBAL_

#define GLOBAL_DEF   8


#endif

main_proj.c

#include <stdio.h>
#include <stdint.h>

#include "global.h"
#include "lib/a.h"

int main( void )
{
    int i = 6;
    a_struct my_a_struct;
    
    a_func( &my_a_struct, i );    
    
    
    printf( "struct: %d,    i said: %d\n", my_a_struct.some_data, ( uint16_t )i );
    printf( "struct global: %d\n", my_a_struct.global_data );
    
    aa_func( &my_a_struct );
    printf( "\nnew data: %d\n", my_a_struct.some_data );
    
    return 0;
}

lib/a.h

#ifndef __A_HEADER_
#define __A_HEADER_

#include <stdint.h>   //want to get rid of these two here
#include "../global.h"  //and have them only in main_proj.c

typedef struct
{
    uint16_t some_data;
    int global_data;
}a_struct;


int a_func( a_struct *the_struct, uint16_t data );
void aa_func( a_struct *the_struct );


#endif

lib/a.c

#include "a.h"  //i can accept this one being here, but again, its included in main_proj.c

int a_func( a_struct *the_struct, uint16_t data )
{
    
    the_struct->some_data = data;
    
    the_struct->global_data = GLOBAL_DEF;
    
    return 0;
}

void aa_func( a_struct *the_struct )
{
    the_struct->some_data++;
}

what am I missing in my understanding of the c linker/preprocessor et al

Last edited by GalacticArachnid (2011-12-08 13:14:15)

Offline

#6 2011-12-08 13:06:21

drcouzelis
Member
From: Connecticut, USA
Registered: 2009-11-09
Posts: 4,092
Website

Re: Noob C question: multiple source files and that

I compiled your code after making a few small changes. The problems are unrelated to having multiple source files.

One thing that may help you to understand what is happening is to keep in mind that, in C, the compiler just starts at the top of the file and reads down, line by line. So, with that in mind...

It tries to compile "a.c". The first thing "a.c" does is include "a.h". When it gets to "uint16_t" it gets confused because it's never seen it before, so you need to "#include <stdint.h>" near the top of "a.h".

Your use of pointers in "a_func()" is a little off. The "->" is used when you are using a pointer. Since "the_struct" is already a pointer, you don't need to use the "*" at the beginning of the line, so it'll look like this instead:

the_struct->some_data = ( uint16_t )data;
the_struct->global_data = GLOBAL_DEF;

Continuing down the file, "a.c" doesn't know what "GLOBAL_DEF" is, because it doesn't know about the "global.h" file. (it was never included in "a.h") You COULD include "../global.h", but it makes more sense (in a real library) to just move the declaration of "GLOBAL_DEF" into "a.h".

Lastly, you had some confusion in your use of structures (which you recently edited out). Which is understandable, because I think the way C defines structures is more confusing than pointers. hmm Your edit works fine (obviously), but you also could have removed the "typedef" keyword to get rid of the warning when you were doing it the first way.

struct a_struct
{
    uint16_t some_data;
    int global_data;
};

You could also combine them and do it both ways: tongue

typedef struct a_struct
{
    uint16_t some_data;
    int global_data;
} a_struct;

Offline

#7 2011-12-08 13:23:16

GalacticArachnid
Member
Registered: 2009-01-02
Posts: 155
Website

Re: Noob C question: multiple source files and that

thank you for the reply drcouzelis,  ive reached most of these conclusions myself just now (and the browser showed no replies so i edited again, to reduce spam posts/log entries)

yes, the main issue it seems is that i expected any files at the end to be able to see what the preprocessor/linker as already added at the start, instead of having a spider web of includes. Basically something like..


a.c needs to include b.h to use b_func
b.c needs to include a.h to use a_func

as an arbitrary example ofc


So, is there a clean workflow to use with multiple header files in projects? Especially if i need to use the same system libraries in a whole bunch of them :s

Offline

#8 2011-12-08 16:10:27

jdarnold
Member
From: Medford MA USA
Registered: 2009-12-15
Posts: 485
Website

Re: Noob C question: multiple source files and that

Just create a 3rd include file that has the stuff the other 2 need, and include that at the top of a & b.

Offline

#9 2011-12-08 20:36:25

drcouzelis
Member
From: Connecticut, USA
Registered: 2009-11-09
Posts: 4,092
Website

Re: Noob C question: multiple source files and that

GalacticArachnid wrote:

So, is there a clean workflow to use with multiple header files in projects? Especially if i need to use the same system libraries in a whole bunch of them :s

The guidelines I follow are:

Put "#define" wrappers around header files. (like you did)

A header file only "#include"s things that are needed in itself, the header file.

A source file only "#include"s things that are needed in itself, the source file.

If there are recursive dependencies between two header files, then only redefine what's needed from the other file instead of using "#include". (this should be rare)

Other than that, it's pretty much just picking a nice directory structure for your files. I usually put the source code for my C programs all in one directory. If you are trying to split up your project into "libraries" while you are working on it, my advice is to NOT do that. Just make an application, and when you finish, if you want to, separate out the code that could become its own library.

Lastly, I recently decided that my separation of data structures was rather arbitrary and that it's better for me to write my C programs in one big file. As I get closer to completing the project, I slowly separate functions and their data structures into their own files. I understand that other programmers might think this is a bad idea, but it seems to work well for me. smile

Offline

Board footer

Powered by FluxBB