Thread: Headerless C programming with a single preprocessor macro line - opinions?

  1. #1
    Registered User milgra's Avatar
    Join Date
    Dec 2013
    Location
    Szeged, HUN
    Posts
    16

    Question Headerless C programming with a single preprocessor macro line - opinions?

    Header files in C can be painful. They duplicate the file count, increase complexity heavily, make refactoring painful.

    There are solutions to get rid of them. It's possible to use header generators ( Makeheaders -- A program to generate header files for C or C++ - makeheaders ), write you own headerless c dialect with a precompiler like me ( GitHub - milgra/clc: Class-C programming language documentation, compiler and core library 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.

    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

    Code:
    #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've created a github repo for this solution : GitHub - milgra/headerless_c: Headerless C programming with a single preprocessor macro line

    At the moment I don't see any pitfalls in this solution, do you? What are your opinions? Thank you.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    36,554
    > At the moment I don't see any pitfalls in this solution, do you?
    That __INCLUDE_LEVEL__ isn't a standard feature means you're stuck with whatever compiler you've chosen.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,335
    Why have you got a header guard (#ifndef mtvec_h) if it's not a header file?

  4. #4
    Registered User milgra's Avatar
    Join Date
    Dec 2013
    Location
    Szeged, HUN
    Posts
    16
    Quote Originally Posted by Salem View Post
    > At the moment I don't see any pitfalls in this solution, do you?
    That __INCLUDE_LEVEL__ isn't a standard feature means you're stuck with whatever compiler you've chosen.
    True, probably won't work with exotic compilers but gcc and clang supports it.

  5. #5
    Registered User milgra's Avatar
    Join Date
    Dec 2013
    Location
    Szeged, HUN
    Posts
    16
    Quote Originally Posted by Hodor View Post
    Why have you got a header guard (#ifndef mtvec_h) if it's not a header file?
    The header part of these hybrid files act as normal headers so they still could be included multiple times in one include tree so double declaration still can happen.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    36,554
    More disadvantages.
    Every time you touch a source file, you're forced to rebuild everything which includes it, even if you didn't change the interface.

    You can't just publish a public interface without exposing the implementation as well. There is no way to stop users peeking at the innards and making use of it. For example, perhaps your implementation contains trade secrets.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User milgra's Avatar
    Join Date
    Dec 2013
    Location
    Szeged, HUN
    Posts
    16
    Quote Originally Posted by Salem View Post
    More disadvantages.
    Every time you touch a source file, you're forced to rebuild everything which includes it, even if you didn't change the interface.

    You can't just publish a public interface without exposing the implementation as well. There is no way to stop users peeking at the innards and making use of it. For example, perhaps your implementation contains trade secrets.
    Thank you! Yes, I was thinking in smaller scope, it is not suitable for bigger/framework projects.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. multiple condition for single variable in single line
    By merafiq in forum C Programming
    Replies: 2
    Last Post: 03-13-2016, 05:26 PM
  2. Command line options for preprocessor directives
    By KemalT in forum C++ Programming
    Replies: 13
    Last Post: 10-18-2014, 08:18 AM
  3. Opinions on line length etiquette?
    By MutantJohn in forum General Discussions
    Replies: 29
    Last Post: 04-28-2014, 08:37 PM
  4. C Preprocessor Macro Question
    By mwpierce in forum C Programming
    Replies: 3
    Last Post: 12-09-2011, 11:34 AM
  5. Replies: 2
    Last Post: 05-15-2007, 03:30 AM

Tags for this Thread