You are not logged in.

#1 2010-03-29 23:17:33

flarkis
Member
From: Tallinn, Estonia
Registered: 2010-02-22
Posts: 8

[solved] C Header Confusion

I'm fairly new to the idea of multi source files in c, but for the most part I have it down. The two problems i have are dealing with non built in types for function declarations.

My problem is that i have a typedef in one header file, i need to use that type in the function declaration of another file along with a type from ncurses. How exactly should i sort that out?

Many Thanks.

in my core.h i have

#ifndef CORE_H
#define CORE_H

typedef struct _life_grid {
  unsigned int new : 1;
  unsigned int old : 1;
} life_grid;

int fill_grid(life_grid **grid, int x, int y, int percent);
int next_gen(life_grid **grid, int x, int y);

#endif

That works fine seeing as the type declaration is in the same file. My big problem comes when adding a second file, ui.h.

#ifndef UI_H
#define UI_H

#include "core.h"
// is this needed?
//#include <ncurses.h>

int print_grid(WINDOW *win, life_grid **grid, int x, int y);
int print_info(WINDOW *win, int turn, int alive, int max_alive);

#endif

and wrap is all up in my main.c file

#include "core.h"
#include "ui.h"

#include <ncurses.h>

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
...

Last edited by flarkis (2010-03-30 03:24:32)

Offline

#2 2010-03-30 00:32:41

cactus
Taco Eater
From: t͈̫̹ͨa͖͕͎̱͈ͨ͆ć̥̖̝o̫̫̼s͈̭̱̞͍̃!̰
Registered: 2004-05-25
Posts: 4,622
Website

Re: [solved] C Header Confusion

think of include as actually expanding your include line to add the entire contents of the header file into your c file.
thus, you simply need to include the core header before you include the ui header file.
You should not need to include one header from inside another header. Just make sure you have the order right.


"Be conservative in what you send; be liberal in what you accept." -- Postel's Law
"tacos" -- Cactus' Law
"t̥͍͎̪̪͗a̴̻̩͈͚ͨc̠o̩̙͈ͫͅs͙͎̙͊ ͔͇̫̜t͎̳̀a̜̞̗ͩc̗͍͚o̲̯̿s̖̣̤̙͌ ̖̜̈ț̰̫͓ạ̪͖̳c̲͎͕̰̯̃̈o͉ͅs̪ͪ ̜̻̖̜͕" -- -̖͚̫̙̓-̺̠͇ͤ̃ ̜̪̜ͯZ͔̗̭̞ͪA̝͈̙͖̩L͉̠̺͓G̙̞̦͖O̳̗͍

Offline

#3 2010-03-30 00:46:34

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [solved] C Header Confusion

Actually I think the header files should usually stand on their own, meaning that you shouldn't have to include anything else if you want to include that file.  All the standard library headers are this way, for example.  I see you're already using include guards, so this shouldn't be too hard to do.  Just make sure every header #includes all its dependencies (inside the include guards, of course).

I always #include my own headers before anyone else's, to make sure I'm following that rule.

Offline

#4 2010-03-30 00:47:02

cmtptr
Member
Registered: 2008-09-01
Posts: 135

Re: [solved] C Header Confusion

Writing an ncurses version of Conway's Game of Life, I guess?  wink

I don't see any problem here except that "#include <ncurses.h" is commented out from ui.h.

Offline

#5 2010-03-30 01:51:22

flarkis
Member
From: Tallinn, Estonia
Registered: 2010-02-22
Posts: 8

Re: [solved] C Header Confusion

thanks for the help, i uncommented the ncurses part and everything is compiling nicely, i could have sworn that it didn't work when i tried.
Although I am still having one problem. The Function i use for randomly generating a board always spits out the same thing?

int fill_grid(life_grid **grid, int x, int y, int percent)
{
  int count, i, j, r;
  count = 0;
  for (i = 0; i < y; i++) {
    for (j = 0; j < x; j++) {
      r = rand() % 101;
      if (r <= percent) {
    grid[i][j].old = 1;
    count++;
      } else {
    grid[i][j].old = 0;
      }
    }
  }
  return count;
}

Last edited by flarkis (2010-03-30 02:14:57)

Offline

#6 2010-03-30 02:50:37

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [solved] C Header Confusion

Do you ever seed the random number generator?  You've got to call srand(time(NULL)) or something, otherwise it'll always be the same.

Offline

#7 2010-03-30 03:24:15

flarkis
Member
From: Tallinn, Estonia
Registered: 2010-02-22
Posts: 8

Re: [solved] C Header Confusion

again a simple mistake, many thanks. Marking thread solved.

Offline

#8 2010-03-30 05:41:12

the_isz
Member
Registered: 2009-04-14
Posts: 280

Re: [solved] C Header Confusion

I haven't coded plain C yet, but in C++ you wouldn't have to include either of
the two headers if you were using forward declarations. As pointers always have
the same size, it's usually unnecessary to include a header as long as you're
not using a type/enum/function defined there, which you don't if I see it
correctly.

Offline

#9 2010-03-30 22:50:20

Trent
Member
From: Baltimore, MD (US)
Registered: 2009-04-16
Posts: 990

Re: [solved] C Header Confusion

the_isz wrote:

I haven't coded plain C yet, but in C++ you wouldn't have to include either of
the two headers if you were using forward declarations. As pointers always have
the same size, it's usually unnecessary to include a header as long as you're
not using a type/enum/function defined there, which you don't if I see it
correctly.

I haven't coded C++ yet, but that made no sense to my C-brain.  I'm guessing the sense of this paragraph depends on the meaning of "forward declarations", which is either a C term I haven't heard or else C++ specific.  Care to elaborate?

By the way, all pointers are not guaranteed to have the same size.  You can avoid any conflicts there by using the guaranteed conversions to and from void *.

Offline

#10 2010-03-30 22:56:16

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: [solved] C Header Confusion

Trent wrote:

I haven't coded C++ yet, but that made no sense to my C-brain.  I'm guessing the sense of this paragraph depends on the meaning of "forward declarations", which is either a C term I haven't heard or else C++ specific.  Care to elaborate?

Forward declarations are like this:

class ThisIsMyClassName;   // forward declaration

// doesn't need full definition of class since it's only taking a pointer
// knowledge that ThisIsMyClassName is a known type is enough
void Method(ThisIsMyClassName* class);   

// later...

class ThisIsMyClassName {
  // full class definition
};

By the way, all pointers are not guaranteed to have the same size.  You can avoid any conflicts there by using the guaranteed conversions to and from void *.

What?  Pointers are memory addresses; for a given architecture, pointer sizes should all be the same (ie. 32 bits on a 32-bit machine, or 64 bits on a 64-bit machine)

Offline

#11 2010-03-30 23:05:51

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [solved] C Header Confusion

Cerebral wrote:

By the way, all pointers are not guaranteed to have the same size.  You can avoid any conflicts there by using the guaranteed conversions to and from void *.

What?  Pointers are memory addresses; for a given architecture, pointer sizes should all be the same (ie. 32 bits on a 32-bit machine, or 64 bits on a 64-bit machine)

Well, the C standard doesn't guarantee that data pointers have the same size as function pointers, but data pointers should all have the same size (and so should function pointers).  In practice, function pointers have the same size as data pointers for most architectures, including anything Arch officially runs on (and any XSI-compliant at all).

C++ gets weirder, because of member function pointers.  These can (and in practice do) have a much different size than regular pointers, because they may encode a vtable offset.

Offline

#12 2010-03-31 01:28:11

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: [solved] C Header Confusion

tavianator wrote:

C++ gets weirder, because of member function pointers.  These can (and in practice do) have a much different size than regular pointers, because they may encode a vtable offset.

Fair enough, I hadn't considered member pointers.  Trumped by a fellow Waterloo-onian.  Waterloo-ite?  Waterloo-itarian?  hm.

Offline

#13 2010-03-31 05:50:10

the_isz
Member
Registered: 2009-04-14
Posts: 280

Re: [solved] C Header Confusion

tavianator wrote:

C++ gets weirder, because of member function pointers.  These can (and in practice do) have a much different size than regular pointers, because they may encode a vtable offset.

Thanks for pointing that out, but I think this doesn't invalidate my suggestion.
flarkis could have safely written

#ifndef UI_H
#define UI_H

struct WINDOW;
struct life_grid;

int print_grid(WINDOW *win, life_grid **grid, int x, int y);
int print_info(WINDOW *win, int turn, int alive, int max_alive);

#endif

as both WINDOW and life_grid are pointers to structures, thus reducing the
size of the object files including this header and - above all - compile time
dependencies.

Offline

#14 2010-04-01 00:20:03

cmtptr
Member
Registered: 2008-09-01
Posts: 135

Re: [solved] C Header Confusion

I have never seen someone code that way before, and it seems like a bad idea simply for reasons of organization and readability (I could be wrong!  let me know).  I use headers exclusively for forward declarations, so I would just #include the header in place of where you typed out "struct WINDOW."  To me this seems to be how headers were intended to be used, and it cuts down on garbage code; imagine writing a types.h header and then re-typedeffing everything at the top of every file.  How redundant!

Offline

#15 2010-04-01 01:01:34

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [solved] C Header Confusion

I'm with cmtptr on this, for two reasons:

1: Abstraction.  The whole point of interfaces like ncurses' is that you don't have to care about what a WINDOW actually is.  Hypothetically it could be an int that ncurses uses as an id.  As a side note, your sample code won't work, because you declare WINDOW to be a struct tag, then write "WINDOW *" instead of "struct WINDOW *".  Furthermore, ncurses.h does "typedef struct _win_st WINDOW;", so we're actually talking about a "struct _win_st*" when we say "WINDOW *".

2: Code clarity.  From your example, I have no idea what a WINDOW * is if I don't work with ncurses a lot.  (I actually thought it was something X related at first.)  But if you #include <ncurses.h>, I have a better idea that the stuff I don't recognise might come from that header.

And, to test your theories about object file size and compile time, I did this:

tavianator@superfluid> cat foo.c                                                                       ~/code
#include <ncurses.h>

int
main()
{
  return 0;
}
tavianator@superfluid> cat bar.c                                                                       ~/code
int
main()
{
  return 0;
}
tavianator@superfluid> time gcc -c -O1 foo.c                                                           ~/code
gcc -c -O1 foo.c  0.01s user 0.00s system 74% cpu 0.022 total
tavianator@superfluid> time gcc -c -O1 bar.c                                                           ~/code
gcc -c -O1 bar.c  0.00s user 0.01s system 66% cpu 0.015 total
tavianator@superfluid> ls -l foo.o                                                                     ~/code
-rw-r--r-- 1 tavianator users 1208 Mar 31 20:59 foo.o
tavianator@superfluid> ls -l bar.o                                                                     ~/code
-rw-r--r-- 1 tavianator users 1208 Mar 31 20:59 bar.o

IOW, 0.07 extra seconds, identical size object files.

Offline

#16 2010-04-01 01:46:20

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: [solved] C Header Confusion

cmtptr wrote:

I use headers exclusively for forward declarations

I suppose that may work well enough in C, so long as you always pass everything by pointer and any struct manipulation is done from within very well contained libraries.

Doesn't work so well in C++ when you need to know the class definition before you can call methods on it though. wink

Offline

#17 2010-04-01 01:52:54

cmtptr
Member
Registered: 2008-09-01
Posts: 135

Re: [solved] C Header Confusion

Cerebral wrote:
cmtptr wrote:

I use headers exclusively for forward declarations

I suppose that may work well enough in C, so long as you always pass everything by pointer and any struct manipulation is done from within very well contained libraries.

Doesn't work so well in C++ when you need to know the class definition before you can call methods on it though. wink

You caught me; I wasn't thinking when I typed that.  I do define structure bodies in headers... my points about why his style is a bad idea still stand, though.

Offline

#18 2010-04-01 05:56:13

the_isz
Member
Registered: 2009-04-14
Posts: 280

Re: [solved] C Header Confusion

Well, I seem be out of my league here as I already stated I've never coded plain
C. In C++, I use forward declarations like that all the time to reduce compile
time dependencies and this indeed does work! (Though I have to admit I never
tested the code I posted and if WINDOW is a typedef it of course won't compile).

tavianator:

It seems that the compiler optimizes here by not including unused definitions.
But now I'm curious... Could you repeat your experiment with a WINDOW pointer
inside your main(), one version including <ncurses.h>, the other omitting it and
forward declaring WINDOW?

I don't know how smart the gcc is, but maybe I'm in luck and this experiment
might be a little closer to what we're actually talking about.

Offline

#19 2010-04-01 16:29:58

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [solved] C Header Confusion

tavianator@superfluid> cat foo.c                                                                       ~/code
#include <ncurses.h>

int
main()
{
  WINDOW *win = newwin(120, 80, 0, 0);
  return 0;
}
tavianator@superfluid> cat bar.c                                                                       ~/code
typedef struct _win_st WINDOW;

WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x);

int
main()
{
  WINDOW *win = newwin(120, 80, 0, 0);
  return 0;
}
tavianator@superfluid> gcc -c -O1 foo.c                                                                ~/code
tavianator@superfluid> gcc -c -O1 bar.c                                                                ~/code
tavianator@superfluid> ls -l foo.o                                                                     ~/code
-rw-r--r-- 1 tavianator users 1368 Apr  1 12:19 foo.o
tavianator@superfluid> ls -l bar.o                                                                     ~/code
-rw-r--r-- 1 tavianator users 1368 Apr  1 12:19 bar.o

What in ncurses.h (or any header, even in C++) do you expect to take up object file space?  Headers generally contain function prototypes, struct/class definitions, definitions of inline functions, and/or definitions of templates.  Technically they could also contain definitions of static functions, but if they're never used, they are easily optimized away.

The only exception that I know in practice is that <iostream> contains some magic to ensure that std::{cin,cout,cerr} are constructed before they could be used.  This usually means creating a global static variable whose constructor initialises them if they haven't already been initialised.

Offline

#20 2010-04-01 16:38:17

the_isz
Member
Registered: 2009-04-14
Posts: 280

Re: [solved] C Header Confusion

tavianator wrote:

What in ncurses.h (or any header, even in C++) do you expect to take up object file space?  Headers generally contain function prototypes, struct/class definitions, definitions of inline functions, and/or definitions of templates.  Technically they could also contain definitions of static functions, but if they're never used, they are easily optimized away.

Well, I'm convinced now, thanks for elaborating. So the only thing that remains
is compile time dependency, but this mainly matters for non-library structs.

Offline

#21 2010-04-11 03:08:22

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [solved] C Header Confusion

tavianator wrote:

... the C standard doesn't guarantee that data pointers have the same size as function pointers, but data pointers should all have the same size (and so should function pointers).

Actually this isn't true, sorry.  C just guarantees that a data pointer can be cast to void * and back, but casting to a different pointer type is undefined.

Offline

#22 2010-04-11 06:55:29

Trent
Member
From: Baltimore, MD (US)
Registered: 2009-04-16
Posts: 990

Re: [solved] C Header Confusion

tavianator wrote:
tavianator wrote:

... the C standard doesn't guarantee that data pointers have the same size as function pointers, but data pointers should all have the same size (and so should function pointers).

Actually this isn't true, sorry.  C just guarantees that a data pointer can be cast to void * and back, but casting to a different pointer type is undefined.

Well, yes.  Almost.  Pointers to composite types (arrays and structs) are convertible to pointers to the first element of the object.  That is, I can convert char (*)[] to char *, and given

struct { int a; } *p;
int *pp = (int *)p;

pp is now &a.  Also, by a cursory reading of the Standard, it would seem that you can cast a null pointer to just about anything and back without losing its null-ness (not very useful).

In practice, all pointers (even function pointers) are likely to have the same size.  However, that's one of those things that C programmers shouldn't have to think about.

Offline

Board footer

Powered by FluxBB