Skip to content

milgra/headerlessc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 

Repository files navigation

Headerless C programming with a single macro definition

Header files in C are painful. They duplicate file count, increase complexity, make refactoring painful. There are solutions to get rid of them. It's possible to use header generators ( https://www.hwaci.com/sw/mkhdr/ - makeheaders ), write you own headerless c dialect with a precompiler like me ( https://github.com/milgra/clc class-c ) or use "#ifdef FOO_IMPLEMENTATION" blocks inside header files to define everything in one file but they are unelegant and confusing and have a lot of other problems.

The ultimate solution seems to be using the __INCLUDE_LEVEL__ preprocessor macro. It's value is zero if we are in a source file that was added directly to the compiler as parameter and greater than zero if we are in a file that was included as a header file from an other file.

So just create a single file, write the header declarations at the top, write the implementation under that and guard the implementation with an #if __INCLUDE_LEVEL__ == 0 macro and you never have to use header files again unless you need a library interface. You can include all files written this way as header files and add these files as source files to the compiler, everything will work as before.

Example : mtvec.c

#ifndef mtvec_h
#define mtvec_h

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

typedef struct mtvec_t mtvec_t;

struct mtvec_t
{
    void** data;
    uint32_t length;
    uint32_t length_real;
};

mtvec_t* mtvec_alloc(void);
void mtvec_dealloc( void* vector );
void mtvec_reset( mtvec_t* vector );

#endif

#if __INCLUDE_LEVEL__ == 0

mtvec_t* mtvec_alloc( )
{
    mtvec_t* vector = mtmem_calloc( sizeof( mtvec_t ) , mtvec_dealloc );
    vector->data = mtmem_calloc( sizeof( void* ) * 10 , NULL );
    vector->length = 0;
    vector->length_real = 10;
    return vector;
}

void mtvec_dealloc( void* pointer )
{
    mtvec_t* vector = pointer;

    for ( uint32_t index = 0 ; index < vector->length ; index++ ) {
    mtmem_release( vector->data[index] );
    }
    mtmem_release( vector->data );
}

void mtvec_reset( mtvec_t* vector )
{
    for ( uint32_t index = 0 ; index < vector->length ; index++ ) mtmem_release( vector->data[index] );

    vector->length = 0;
}

#endif

I created/maintain seven applications so far in headerless C and haven't faced any drawbacks yet, feel free to try them :

About

Headerless C programming with a single preprocessor macro line

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published