C Structure multiple files

Code junkies hangout here

Moderators: ChrisThornett, LXF moderators

C Structure multiple files

Postby Crispy » Wed Oct 31, 2012 12:58 pm

Hi,

I have been playing around a little bit with C but have come across a problem which I can't seem to get my head around. I have a main file which contains a structure:

main.c
Code: Select all
#include <stdio.h>
#include <stdlib.h>

#include "test.h"

struct test
{
  int t1;
  int t2;
};

static struct test t;

int main( int argc, char **argv )
{
  int err = 0;
  t.t1 = 0;
  t.t2 = 0;

  err = test_struct_fnc( &t );

  printf("t.t1 = %d\n", t.t1);
  printf("t.t2 = %d\n", t.t2);

  return 0;
}


It includes the file test.h which simply contains a function prototype:

test.h
Code: Select all
int test_struct_fnc( struct test *t__i );


This function is then found in test.c:

test.c
Code: Select all

int test_struct_fnc( struct test *t__i )
{
  t__i->t1 = 10;
  t__i->t2 = 100;
}


which simply changes the values of t1 and t2 to 10 and 100 respectively. However, when I compile:

Code: Select all
gcc -g -c test.c
gcc -g -c main.c
gcc -g -o test.exe test.o main.o


I get an error from test.c saying:

Code: Select all
test.c:1: warning: ‘struct test’ declared inside parameter list
test.c:1: warning: its scope is only this definition or declaration, which is probably not what you want
test.c: In function ‘test_struct_fnc’:
test.c:3: error: dereferencing pointer to incomplete type
test.c:4: error: dereferencing pointer to incomplete type


I think this is because the structure test is declared in main not in test.c. However declaring the structure to be external - extern struct test; - in test.h doesn't work it still gives the same error.

I thought that perhaps changing struct test to typedef struct test would help, however I can't figure out how to share the type definition across the multiple files? I tried

Code: Select all
 extern typedef test;


In the header file test.h however that gave an error saying it expected a ) before * token in test.c - which makes no sense to me. I just can't figure out what I'm supposed to do here so any help would be greatly appreciated.

Thanks in advance,
Chris
Crispy
 
Posts: 57
Joined: Mon May 31, 2010 6:35 pm

Postby Crispy » Wed Oct 31, 2012 3:30 pm

I figured out a way around it, place all typedefs in a header file then include that header file in anything that requires those typedefs. For example:

typedefs.h
Code: Select all
#ifndef TEST_H_FILE
#define TEST_H_FILE

typedef struct testy
{
  int t1;
  int t2;
} test;

#endif


The #ifndef directive is to prevent multiple definition as the file will be included in lots of different source files. I am curious as to whether there is another way to do it, anyone have any ideas?

Thanks,
Chris
Crispy
 
Posts: 57
Joined: Mon May 31, 2010 6:35 pm

Re: C Structure multiple files

Postby CJLL » Sun Nov 11, 2012 5:09 pm

Crispy wrote:Hi,

Code: Select all
int test_struct_fnc( struct test *t__i )



The keyword struct tells the compiler that you are defining a new data type, and shouldn't be used in a function parameter list. :roll:
--
The reward for self love is sticky hands
CJLL
LXF regular
 
Posts: 193
Joined: Sat Jul 09, 2005 9:22 pm

Postby einonm » Wed Nov 14, 2012 12:22 pm

Crispy wrote:I figured out a way around it, place all typedefs in a header file then include that header file in anything that requires those typedefs.

The #ifndef directive is to prevent multiple definition as the file will be included in lots of different source files. I am curious as to whether there is another way to do it, anyone have any ideas?


Hi Chris,

You've discovered correctly that structures shared between many source files need to be placed in a header file and #included in those source files. This is the right thing to do.

A few other points are:

1. You don't need to typedef the struct, just putting the struct definition into the header file will be fine - and preferable, as it doesn't hide the fact that it's a struct (as opposed to an enum or int, for example).

2. If you #include the header file containing the struct definition, there is no need to declare it as extern, just use it. Try and avoid using extern if you can.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." --Brian Kernighan
einonm
 
Posts: 29
Joined: Fri Apr 20, 2012 10:19 am
Location: Cardiff, UK

Re: C Structure multiple files

Postby einonm » Wed Nov 14, 2012 12:26 pm

CJLL wrote:The keyword struct tells the compiler that you are defining a new data type, and shouldn't be used in a function parameter list.


Yes, the compiler thinks that a new struct is being defined, only because it can't find the definition elsewhere. Putting the struct definition in the header file above the function declaration would solve this.

Using the keyword 'struct' in a function parameter list is the correct thing to do, the only way to get around this is to typedef the struct, which I wouldn't recommend doing - so the function declaration is all good, just missing the struct definition.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." --Brian Kernighan
einonm
 
Posts: 29
Joined: Fri Apr 20, 2012 10:19 am
Location: Cardiff, UK

Postby Crispy » Fri Feb 08, 2013 11:57 am

Thank you for your replies and my apologies for such a delayed response. Thank you as well for the tips :).

I have a couple of new questions if that's ok? If I used malloc to allocate some memory, is that memory contiguous? I think that's the right phrasing - i.e. each element of the array is next to each other? If so does that still hold for 2D arrays? If it isn't, would it be more efficient to make it contiguous?

My next question is a bit difficult to explain - lets assume I have 3 files. A main file, main.c, a header file which contains nothing but data, data.h - for example:
Code: Select all
int p;
int *ptr;

and a file funcs.c which contains a function testfnc (also have funcs.h - only has function prototype). The main file includes data.h and funcs.h, however funcs.c only includes funcs.h. The function testfnc is then called from the main file. Is it more efficient to pass the integer p from data.h to the function testfnc as an argument or include the data.h file in funcs.c? I.e. from the main file: testfnc( p ); or testfnc();?

Finally, if the function testfnc has to allocate memory (using malloc or calloc), say a large array, and the function testfnc is called from the main file within a for loop, is it more efficient to create a kind of constructor in funcs.c that is called outside the loop and allocate all of the memory (assuming a fixed size) prior to calling testfnc? Rather than allocating and deallocating the memory each time testfnc is called?

I hope that makes sense, it was kind of difficult to explain.

Thanks in advance,
Chris
Crispy
 
Posts: 57
Joined: Mon May 31, 2010 6:35 pm

Postby einonm » Fri Feb 08, 2013 12:14 pm

Crispy wrote:Thank you for your replies and my apologies for such a delayed response. Thank you as well for the tips :).

I have a couple of new questions if that's ok? If I used malloc to allocate some memory, is that memory contiguous? I think that's the right phrasing - i.e. each element of the array is next to each other? If so does that still hold for 2D arrays? If it isn't, would it be more efficient to make it contiguous?


It's virtually contiguous, in that the addresses are a contiguous range. It's not guaranteed to be physically contiguous though - heck, the memory may not even exist yet due to the kernel using something called 'over committing'. There are special ways of asking for physically contiguous memory (e.g. for fast graphics operations). I think at this level, you don't need to worry about it.

Crispy wrote:My next question is a bit difficult to explain - lets assume I have 3 files. A main file, main.c, a header file which contains nothing but data, data.h - for example:
Code: Select all
int p;
int *ptr;

and a file funcs.c which contains a function testfnc (also have funcs.h - only has function prototype). The main file includes data.h and funcs.h, however funcs.c only includes funcs.h. The function testfnc is then called from the main file. Is it more efficient to pass the integer p from data.h to the function testfnc as an argument or include the data.h file in funcs.c? I.e. from the main file: testfnc( p ); or testfnc();?

Finally, if the function testfnc has to allocate memory (using malloc or calloc), say a large array, and the function testfnc is called from the main file within a for loop, is it more efficient to create a kind of constructor in funcs.c that is called outside the loop and allocate all of the memory (assuming a fixed size) prior to calling testfnc? Rather than allocating and deallocating the memory each time testfnc is called?

I hope that makes sense, it was kind of difficult to explain.

Thanks in advance,
Chris


This code probably won't work. You can only _declare_ variables in header files, you must _define_ a variable in a .c file to use it (and then use the 'extern' keyword in the header to share it). This is because a variable declaration doesn't allocate any memory for the variable, only the variable definition does that. After the compiler gets it's hands on the code, it doesn't matter where the declarations are - you're still accessing the same memory, regardless of which c file it is in. Obviously passing that variable as a parameter involves another copy, so is less efficient (but more secure and less bug-prone), than a 'global' variable.

Again, for individual variables on a modern computer at this level, you really shouldn't care about these issues. Just write the code to do something useful!

Cheers,

Mark
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." --Brian Kernighan
einonm
 
Posts: 29
Joined: Fri Apr 20, 2012 10:19 am
Location: Cardiff, UK

Postby einonm » Fri Feb 08, 2013 12:22 pm

Crispy wrote:Finally, if the function testfnc has to allocate memory (using malloc or calloc), say a large array, and the function testfnc is called from the main file within a for loop, is it more efficient to create a kind of constructor in funcs.c that is called outside the loop and allocate all of the memory (assuming a fixed size) prior to calling testfnc? Rather than allocating and deallocating the memory each time testfnc is called?
Chris


Er, yes. Allocate once and not many times is better, probably...
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." --Brian Kernighan
einonm
 
Posts: 29
Joined: Fri Apr 20, 2012 10:19 am
Location: Cardiff, UK

Postby Crispy » Fri Feb 08, 2013 12:43 pm

Thank you for your reply einonm.
It's virtually contiguous, in that the addresses are a contiguous range. It's not guaranteed to be physically contiguous though - heck, the memory may not even exist yet due to the kernel using something called 'over committing'. There are special ways of asking for physically contiguous memory (e.g. for fast graphics operations). I think at this level, you don't need to worry about it.

Yeah don't think I need to worry about over committing or anything like that, maybe in the future :D.
This code probably won't work. You can only _declare_ variables in header files, you must _define_ a variable in a .c file to use it (and then use the 'extern' keyword in the header to share it). This is because a variable declaration doesn't allocate any memory for the variable, only the variable definition does that.

Yeah, sorry I don't think I explained it very well. Basically in the header file I declare all the data I require for the program. That data is then initialised in the main file so assume that p was set to be 10 for example before testfnc was called.
Er, yes. Allocate once and not many times is better, probably...

Yeah I thought it would be, the thing is I've got a loop:
Code: Select all
for (i = 0; i < 100; i++)
    testfnc( p );

where testfnc then allocates a 1D array of size 40,000, then deallocates before leaving:
Code: Select all
void testfnc( int j )
{
    double *test;

    test = (double *) malloc( 40000 * sizeof(*test) );

    free(test);
}

The size of the array testfnc allocates doesn't change in the 100 iterations so I thought it might be more efficient. Perhaps I'll do a test.

Thanks again,
Chris
Crispy
 
Posts: 57
Joined: Mon May 31, 2010 6:35 pm


Return to Programming

Who is online

Users browsing this forum: No registered users and 4 guests