You are not logged in.
I am programming in C and I want to improve my style and quality of code.
I would like to know the best way to structure a header and what kind of things I should be placing in headers versus in main? what things should I compile as stand alone C files?
The way I do things now is basically use headers as a store house for functions that fall under a general umbrella.
For example if the program is pretty big and implements a lot of different things I may use one header for all the file manipulation functions like sorting, creating, removing etc. (essentially making a mini-library) and I may use another header for network functions like sending the files etc. All while main is just the general structure of the program, and it's where I apply threads and general program flow all while the real power comes from the headers and functions. I try to keep main pretty minimal.
Is this bad coding practice? I am pretty much self taught so I would like to know if I am doing something wrong.
Offline
Headers are usually just function prototypes. The implementation goes in the .c file.
Offline
That is basically what I have been doing. I basically make functions in main and when they work I pull them out and toss them in a header that falls under the 'umbrella' of its use.
Offline
It sounds like you are putting the whole function in the header, which is different than just putting the prototype in...
Offline
When I mean toss it it, I mean the prototype. I cut the declaration out.
I would put something like this in a header:
int add(int x, int y){
return x+y;
}
^this is a prototype right?
Last edited by Google (2010-09-18 13:15:22)
Offline
When I mean toss it it, I mean the prototype. I cut the declaration out.
I would put something like this in a header:
int add(int x, int y){
return x+y;
}^this is a prototype right?
No, this is the function definition. The prototype is the declaration of this function, conceptually the initial line without the body, like in your example:
int add(int x, int y);
Last edited by bernarcher (2010-09-18 13:30:18)
To know or not to know ...
... the questions remain forever.
Offline
So the header contains the declarations, and the .c contains the definitions? I think I had it backwards!
Offline
So the header contains the declarations, and the .c contains the definitions? I think I had it backwards!
There's a "you had your head up your ass" joke in here somewhere, but I can't find it.
My Arch Linux Stuff • Forum Etiquette • Community Ethos - Arch is not for everyone
Offline
Hmm, reminds me of an article I read about people who insist on putting an X in their online alias.
Offline
Typically a project will have pairs of files with the same name but different extensions -- stuff.c contains definitions whereas stuff.h contains delcarations of the things stuff.c wants to export to other places. When writing a program that uses stuff, you put #include "stuff.h" in your main file and compile stuff.c and main.c separately, then link together stuff.o and main.o into an executable.
The purpose of header files is to check the correct use of external data and functions at compile time without having to recompile it all whenever you change any single file. If you put definitions in your header files, you're essentially copying your whole project into one file at compile time. For large projects you could waste hours recompiling the entire thing because you made a minor change in main() -- not good.
Offline
That makes sense. I haven't worked on any large project but I do like separating code because it makes things more readable, and you can re-use a lot of code from certain things.
Offline
Similar for libraries. One day, take a look at the headers you use.
aur S & M :: forum rules :: Community Ethos
Resources for Women, POC, LGBT*, and allies
Offline
In .h you should put
int add(int, int);
Offline
By no means any kind of public standard that I know of, but the following is an example of my typical standard practices.
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <pathHeaders.h>
#include "localHeaders.h"
/* macros specific to this module are prefixed with the module name */
#define WIDGET_MACRO 123
/* if a tag is necessary, use the typedef name preceeded by an underscore */
typedef struct _Widget {
char *whatev;
int hello;
struct _Widget *next;
} Widget;
/* functions and global variables (ew!) specific to this
module are prefixed with the module name and an underscore */
/* short description of this function */
extern int widget_wiggleWoggle(
Widget *this,
const Widget *that
);
/* malloc and initialize a widget */
extern Widget *widget_new(
char *whatev,
int hello
);
/* uninitialize and free a widget */
extern void widget_free(
Widget *this
);
#endif /* WIDGET_H */
widget.c:
#include <assert.h>
#include <otherPathHeaders.h>
#include <stdlib.h>
#include "localHeaders.h"
#include "widget.h"
/* static functions and variables private to this
module are preceeded with one underscore */
static Widget *_lastWiggled;
static void _staticFunction(int *dest, int src)
{
/* don't assert parameters in private functions;
assume the extern'd functions already asserted them */
*dest |= src;
*dest <<= 1;
}
int widget_wiggleWoggle(Widget *this, const Widget *that)
{
size_t i;
assert(this);
assert(that);
for (i = 0; i < sizeof this->hello; i ++) {
_staticFunction(&this->hello, that->hello);
}
_lastWiggled = this;
return this->hello;
}
Widget *widget_new(char *whatev, int hello)
{
Widget *this;
assert(whatev);
this = malloc(sizeof *this);
if (!this)
return 0;
/* do necessary stuff to initialize this */
this->whatev = whatev;
this->hello = hello;
return this;
}
void widget_free(Widget *this)
{
assert(this);
/* do necessary stuff before freeing this */
if (_lastWiggled == this)
_lastWiggled = 0;
free(this);
}
Last edited by cmtptr (2010-09-18 21:14:32)
Offline
You'll also generally put inline functions in the header files as well.
Offline
You'll also generally put inline functions in the header files as well.
You would? Why?
Offline
codycarey wrote:You'll also generally put inline functions in the header files as well.
You would? Why?
Because if you put normal function in header file, it will cause conflict, but not inline function.
You should also read boost library, which is almost entirely written in c++ header files. Not much you can do with c header files though, maybe some macro programming.
Last edited by yejun (2010-09-19 05:37:52)
Offline
/* short description of this function */ extern int widget_wiggleWoggle( Widget *this, const Widget *that );
extern is implied for function declarations.
Because if you put normal function in header file, it will cause conflict, but not inline function.
Another option is to make the functions static, which usually has the same result as inline.
Offline
Thanks, that makes a lot of sense!
Offline
Another option is to make the functions static, which usually has the same result as inline.
Not at all. static in a file-scope function declaration gives the identifier internal linkage, which basically means that it isn't visible from any other source code file. Referencing a function with internal linkage from some other file is a link-time error. inline tells the compiler that a particular function definition is a good candidate for inlining, which means that no object code is generated and the content of the function is inserted in-line wherever the function is called. Inline functions must always be defined in every file in which they are declared, which is why they are good candidates for placing in header files. Using an inline function that hasn't been defined is a compile-time error, although for semantic reasons I think it can't be detected until link time.
It's true that inline is only a suggestion to the compiler, and so it's quite possible that inline and static occasionally have apparently the same effect. But by no means are they interchangeable, and there's nothing useful that can be learned from conflating the two meanings.
As an aside, I forgot to mention this, but cmptr used it: your .c file should include the .h file of the same name (widget.c #includes "widget.h"). This ensures that the interface you export to other files is compatible with the internal workings of the program; e.g. it will raise a compile-time error if you declare "double val;" in the header and "float val;" in the .c file.
Offline
Not at all. static in a file-scope function declaration gives the identifier internal linkage, which basically means that it isn't visible from any other source code file. Referencing a function with internal linkage from some other file is a link-time error. inline tells the compiler that a particular function definition is a good candidate for inlining, which means that no object code is generated and the content of the function is inserted in-line wherever the function is called. Inline functions must always be defined in every file in which they are declared, which is why they are good candidates for placing in header files. Using an inline function that hasn't been defined is a compile-time error, although for semantic reasons I think it can't be detected until link time.
It's true that inline is only a suggestion to the compiler, and so it's quite possible that inline and static occasionally have apparently the same effect. But by no means are they interchangeable, and there's nothing useful that can be learned from conflating the two meanings.
I was commenting on having the function definition in the header file... in which case I now realize you have to make the function static whether you use inline or not.
Offline
I was commenting on having the function definition in the header file... in which case I now realize you have to make the function static whether you use inline or not.
That's not true at all. There's different semantics for inline depending on which standard you're using (GNU C89, ISO C99, and C++). Briefly, for GNU C89, all inline function definitions should say "extern inline" except one, which should just say "inline". For C99, all inline function definitions should say "inline" except one, which should have "inline" left out. And for C++, everything should just say "inline". You can read more here.
And here's some macros I once wrote to automate the whole process.
Offline
By no means any kind of public standard that I know of, but the following is an example of my typical standard practices...
The examples from cmtptr look very similar to my code, although I don't use "static" on any function declarations, and I pretty much never use the "inline" and "extern" commands.
One big difference in my code is something I started doing recently: I put as few "#include" commands in a header file as possible. Instead, in my header file I add as many re-declarations as needed (I only end up needing them for "struct" and "enum" declarations) and put all of my "#include" commands in the ".c" file. The benefit of this is that it removes most problems when I need to do something like circular dependency. (for example, struct A has a pointer to a struct B which has a pointer to a struct A)
Ah, what the heck, here's an example from my project.
Header:
#ifndef WORLD_HEADER
#define WORLD_HEADER
#include <allegro.h>
#define MAX_ROOMS 40
typedef struct WORLD WORLD;
struct PLAYER;
struct ROOM;
typedef enum
{
STORY_WORLD = 0,
ENDLESS_WORLD
} WORLD_TYPE;
struct WORLD
{
/**
* What type of world this is.
*/
WORLD_TYPE type;
/**
* Represents the player, aka the hero!
*/
struct PLAYER *player;
/**
* A list of the rooms in this world.
*/
struct ROOM *rooms[MAX_ROOMS];
int num_rooms;
int room_idx;
/**
* The room number that is currently occupied.
* This may be greater than the number of rooms that
* are currently in the world.
*/
int room_num;
};
WORLD *create_world();
void destroy_world(WORLD *world);
void add_room(WORLD *world, struct ROOM *room);
void clear_rooms(WORLD *world);
void update_world(WORLD *world);
void paint_world(WORLD *world, BITMAP *canvas);
#endif
Source:
#include "character.h"
#include "player.h"
#include "room.h"
#include "sprite.h"
#include "world.h"
WORLD *create_world()
{
WORLD *world;
int i;
world = malloc(sizeof(WORLD));
world->type = STORY_WORLD;
world->player = create_player();
warp_sprite(world->player->character->sprite, ROWS - 3, COLS / 2);
for (i = 0; i < MAX_ROOMS; i++) {
world->rooms[i] = NULL;
}
world->num_rooms = 0;
world->room_idx = 0;
world->room_num = 0;
return world;
}
void destroy_world(WORLD *world)
{
if (world == NULL) {
return;
}
destroy_player(world->player);
clear_rooms(world);
free(world);
}
void add_room(WORLD *world, ROOM *room)
{
if (world == NULL || room == NULL) {
return;
}
world->rooms[world->num_rooms] = room;
world->num_rooms++;
}
void clear_rooms(WORLD *world)
{
int i;
if (world == NULL) {
return;
}
for (i = 0; i < MAX_ROOMS; i++) {
destroy_room(world->rooms[i]);
}
}
void update_world(WORLD *world)
{
update_player(world->player, world);
update_room(world->rooms[world->room_idx]);
}
void paint_world(WORLD *world, BITMAP *canvas)
{
paint_room(world->rooms[world->room_idx], canvas);
paint_sprite(world->player->character->sprite, canvas);
}
Offline