lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

It was thus said that the Great joao lobato once stated:
> On 10/18/11, Patrick Mc(avery <> wrote:
> >
> > It should be easier for a single developer to split code between files.
> >
> In C, is it possible to do something like this?
> int function(int a){
>   int b;
>   #include "other_file.h"
>   return a + b;
> }
> // other_file.h
> b = 42;

  Yes, that will work.  I, personally, don't like it, and will never do such
a thing again (yes, a bit on this below), but yes, it will work.  In fact,
you can abuse the C preprocessor quite a bit.  Back in my university days, I
implemented a template like system for C using the C preprocessor.  Here's a
bit of code to give a sample of what it was like:

	------[ vs_int.h ]----------

	#include "vs_stack.h"
	#include "vs_string.h"
	#include "vs_undef.h"

	#define T_TYPE          int
	#define T_PREFIX        int
	#define T_NTYPE         T_INT
	#define T_STACK         stack_data
	#define T_RETV          0
	#define T_CELL          i

	#define CONST
	#define VAR
	#define LIT
	#define FETCH
	#define STORE
	#define ADD
	#define SUB
	#define MULT
	#define DIV
	#define MOD

	/* ... */

	#include "vs_ops.h"

	/* ... */

	#include "vs_ops.c"

This would define such functions as int_var() and int_fetch() as well as
int_push() and int_pop() (the code in question implemented a Forth-like
lanuage) using such questionable constructs like:

	-------[ vs_ops.h ]-----------

	#define __MKFUNCTION(x,y)       x ## y
	#define _MKFUNCTION(x,y)        __MKFUNCTION(x,y)

	#define __MKPRIVATE(x,y)        _P_ ## x ## y
	#define _MKPRIVATE(x,y)         __MKPRIVATE(x,y)


	#ifdef _DEF
	void    _MKFUNCTION(T_PREFIX,_push)     (T_TYPE);
	T_TYPE  _MKFUNCTION(T_PREFIX,_pop)      (void);

	#ifdef CONST
	#ifdef _DEF
	void    _MKFUNCTION(T_PREFIX,_const)    (void);
	void    _MKFUNCTION(T_PREFIX,_constq)   (void);
	void    _MKPRIVATE(T_PREFIX,_doconst)   (void);
	{ "const" , _MKFUNCTION(T_PREFIX,_const) , F_NOF | F_CODE },
	{ "const'" , _MKFUNCTION(T_PREFIX,_constq) , F_NOF | F_CODE },

	#ifdef VAR
	#ifdef _DEF
	void    _MKFUNCTION(T_PREFIX,_var)      (void);
	void    _MKFUNCTION(T_PREFIX,_varq)     (void);
	void    _MKPRIVATE(T_PREFIX,_dovar)     (void);
	void    _MKFUNCTION(T_PREFIX,_sizeof)   (void);
	void    _MKFUNCTION(T_PREFIX,_matrix)   (void);
	void    _MKFUNCTION(T_PREFIX,_matrixq)  (void);
	void    _MKPRIVATE(T_PREFIX,_domatrix)  (void);
	{ "var" , _MKFUNCTION(T_PREFIX,_var) , F_NOF | F_CODE },
	{ "var'" , _MKFUNCTION(T_PREFIX,_varq) , F_NOF | F_CODE },
	{ "sizeof",_MKFUNCTION(T_PREFIX,_sizeof), F_NOF | F_CODE } ,
	{ "matrix",_MKFUNCTION(T_PREFIX,_matrix), F_NOF | F_CODE } ,
	{ "matrix'",_MKFUNCTION(T_PREFIX,_matrixq), F_NOF | F_CODE } ,

Ugly as hell and hard to use.  Going back to vs_int.h, notice how it
includes vs_string.h?  What does vs_string.h look like?

	------[ vs_string.h ]-------

	#include "vs_undef.h"

	#define T_TYPE          char *
	#define T_PREFIX        string
	#define T_NTYPE         T_STRING
	#define T_STACK         stack_data
	#define T_RETV          NULL
	#define T_CELL          p
	#define LIT
	#define _DEF
	/* ... */
	#include "vs_ops.h"

	/* ... */

	#include "vs_ops.c"

Yeah, vs_ops.h is included multiple times, to generate broilerplate code. 
vs_undef.h basically undefines a bunch of defines, so they can be redefined
again.  vs_ops.c contains code like:

	------[ vs_ops.c ]----------
	#ifdef LIT
	void _MKFUNCTION(T_PREFIX,_plitp)(void)
	  union cell  *pc;
	  pc = return_pop();

  The end result---very fragile code (you need to understand *exactly* what
to include, when to include it, and how to do so) that is difficult to
maintain (I haven't touched this code in fifteen years).  When developing
it, I had to learn rather quickly how to get the output from the
preprocessing stage so I could debug not C code, but C preprocessing code.  

  It's code like this (and I'm glad I made this mistake before I got into
industry) that leads professional programmers to Just Say No to including
code in this manner.  Sure, you may be saving yourself some typing now, but
just wait until you have to maintain such code.

  -spc (All too often though, programmers that continue to do this don't
	have to maintain their own mistakes [1])

[1]	I used to work in a web hosting/development company.  One of our
	clients bought a CGI program (written in C---this was back in 1996
	or there abouts) from some programmer.  The program didn't quite
	work as advertised, but the programmer refused to fix the code,
	saying, and I quote, "I got paid.  Now fuck off."

	Tricks used where including files in odd places, random indentations
	(really!  No structure what-so-ever; and remember, this was C code!)
	and badly named variables.  My wish, as I was trying to debug this
	crap, was to force the original programmer to fix his own
	*wonderful* code.  Or short of that, have the guy executed.

	It ended up being easier to rewrite the program from scratch than to
	fix the original code.

	Yes, I'm still bitter about it.