[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Panda Bears will die, Sloths will live on
- From: Sean Conner <sean@...>
- Date: Tue, 18 Oct 2011 17:04:03 -0400
It was thus said that the Great joao lobato once stated:
> On 10/18/11, Patrick Mc(avery <patrick@spellingbeewinnars.org> 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)
#endif
#ifdef _DEF
void _MKFUNCTION(T_PREFIX,_push) (T_TYPE);
T_TYPE _MKFUNCTION(T_PREFIX,_pop) (void);
#endif
#ifdef CONST
#ifdef _DEF
void _MKFUNCTION(T_PREFIX,_const) (void);
void _MKFUNCTION(T_PREFIX,_constq) (void);
void _MKPRIVATE(T_PREFIX,_doconst) (void);
#else
{ "const" , _MKFUNCTION(T_PREFIX,_const) , F_NOF | F_CODE },
{ "const'" , _MKFUNCTION(T_PREFIX,_constq) , F_NOF | F_CODE },
#endif
#endif
#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);
#else
{ "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 } ,
#endif
#endif
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();
_Stack_push(*pc,&T_STACK,T_NTYPE);
pc++;
return_push(pc);
}
#endif
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.