[comp.lang.c] NULL as a string terminator

evil@arcturus.uucp (Wade Guthrie) (08/08/90)

Gary Duzan writes:
>=>     char command[15];
>=>     command[strlen(command)-1]=NULL; /* chop off the \n */

and Doug Gwyn says:
> You're correct; the example code would happen to work with the traditional
> definition of NULL as plain 0, but not if it's defined as ((void*)0).

That is why I have made it a practice to define a macro:

#define	NULLchar	'\0'

in order to reduce the confusion/broken code.  One thing that I find
helpful is to have a header file called "global.h" or "wade.h" that
has a bunch of definitions I use in all my code.  This file is included
by every C file and has things in it like:

#define	YES	1
#define	NO	0
#ifdef	MAIN_MODULE
	int		my_debug = 0;
#else
	extern int 	my_debug;
#endif

I find this to be very useful (the file is actually quite a bit bigger
than this, but I don't think anyone really cares. . .)
-- 
Wade Guthrie (evil@arcturus.UUCP)    | "He gasped in terror at what sounded
Rockwell International; Anaheim, CA  | like a man trying to gargle while
My opinions, not my employer's.      | fighting off a pack of wolves"
                                     |                Hitchhiker's Guide

darcy@druid.uucp (D'Arcy J.M. Cain) (08/10/90)

In article <1990Aug7.210152.7586@arcturus.uucp> evil@arcturus.uucp (Wade Guthrie) writes:
>and Doug Gwyn says:
>> You're correct; the example code would happen to work with the traditional
>> definition of NULL as plain 0, but not if it's defined as ((void*)0).
>That is why I have made it a practice to define a macro:
>#define	NULLchar	'\0'
>
Can someone explain to me what is wrong with using '\0' or even 0 when a
zero byte is required.  Is there ever a possibility that NULLchar or
whatever will evaluate to anything but a zero byte.  Perhaps this is for
people who get paid by the line of code.

Let's see.  If I was paid by the line of code ...

#define IF if
#define ELSE else
#define LOOP_WHILE_STATEMENT_TRUE(x) while(x)
#define DO_IF_STATEMENT_TRUE(x) IF(x)
etc

I bet I could turn "Hello, world" into a major GNU project. :-)

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   MS-DOS:  The Andrew Dice Clay
West Hill, Ontario, Canada         |   of operating systems.
+ 416 281 6094                     |

meissner@osf.org (Michael Meissner) (08/10/90)

In article <1990Aug7.210152.7586@arcturus.uucp> evil@arcturus.uucp
(Wade Guthrie) writes:

| Gary Duzan writes:
| >=>     char command[15];
| >=>     command[strlen(command)-1]=NULL; /* chop off the \n */
| 
| and Doug Gwyn says:
| > You're correct; the example code would happen to work with the traditional
| > definition of NULL as plain 0, but not if it's defined as ((void*)0).
| 
| That is why I have made it a practice to define a macro:
| 
| #define	NULLchar	'\0'

I really don't understand why the NULLchar macro is any clearer than
just '\0'.  But then, I really have never seen the need for NULL
either (the appropriate cast of 0 works just as well -- if you have
problems with the shift key, then maybe you should learn to type :-)
--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142

Do apple growers tell their kids money doesn't grow on bushes?

robert@cs.arizona.edu (Robert J. Drabek) (08/11/90)

D'Arcy J.M. Cain writes:

> Wade Guthrie writes:
> >I have made it a practice to define a macro:
> >#define  EOS  '\0'

> Can someone explain to me what is wrong with using '\0' or even 0 when a
> zero byte is required.  Perhaps this is for people who get paid by the 
> line of code.

Nothing really `wrong' with it.  I see the difference as one between
using an object and using a name for the object.  My personal feeling is
that it is more polite to use the name.  Or maybe it's like licking your
lips and rubbing your stomach instead of expressing yourself in words.
(Forgive me, but it's 5:30 pm and I should be heading home for dinner.)

Also, EOS is easier for me to type when changing from one keyboard to
another as the ', \, and 0 often vary in position and are all further
from the home row.  But even if I had an abbreviation set up (in vi) I'd
still like to read the EOS instead.

The reason why requires maybe one last explanation which is more
objective.  '\0' has uses and interpretations other than "end-of-
string".  So when I see EOS I know for certain what I meant.  When I see
'\0' there is the chance that some other interpretation or use is meant.

--
-- 
Robert J. Drabek                            robert@cs.Arizona.EDU
Department of Computer Science              uunet!arizona!robert
The University of Arizona                   602 621 4326
Tucson, AZ  85721

skrenta@blekko.UUCP (Rich Skrenta) (08/11/90)

robert@cs.arizona.edu (Robert J. Drabek) writes:

>>> #define  EOS  '\0'

> I see the difference as one between
> using an object and using a name for the object.  My personal feeling is
> that it is more polite to use the name.

> '\0' has uses and interpretations other than "end-of-
> string".  So when I see EOS I know for certain what I meant.  When I see
> '\0' there is the chance that some other interpretation or use is meant.

In many cases the object itself becomes familiar enough that it's
instantly recognized.  '\0' is one such object.  If I saw in your
code

	*p = EOS;

I'd have to run off to your .h files to find the definition of EOS.
*You* like your non-standard name for '\0', but no one else will
know what it means, and it's unlikely that it will ever be a Big Win
for you (like if we start terminating strings with ^A or something).

Other cases occur where someone makes #defines for error strings
that are used only once:

#define	FOO_BAR_ERROR	"foo bar error"
#define UNDEF_BAZ_ERR	"undef baz err"

I cringe when I come across code like this.  Needlessly removing objects
a level is distracting and gains nothing.

Rich
-- 
skrenta@blekko.commodore.com

cbp@icc.com (Chris Preston) (08/20/90)

In article <134@blekko.UUCP> skrenta@blekko.UUCP (Rich Skrenta) writes:
>robert@cs.arizona.edu (Robert J. Drabek) writes:
>
>>>> #define  EOS  '\0'
>
>> I see the difference as one between
>> using an object and using a name for the object.  My personal feeling is
>> that it is more polite to use the name.
>
>> '\0' has uses and interpretations other than "end-of-
>> string".  So when I see EOS I know for certain what I meant.  When I see
>> '\0' there is the chance that some other interpretation or use is meant.
>
>In many cases the object itself becomes familiar enough that it's
>instantly recognized.  '\0' is one such object.  If I saw in your
>code
>
>	*p = EOS;
>
>I'd have to run off to your .h files to find the definition of EOS.

  Perhaps a comment in an appropriate place might alleviate this.

>*You* like your non-standard name for '\0', but no one else will
>know what it means, and it's unlikely that it will ever be a Big Win
>for you (like if we start terminating strings with ^A or something).

  Then, it will be a very big win.  Using two characters would break
  much more software than would changing the terminator to a single
  different letter.  In the case of doing a sprinkling of assembly
  on DOS or CPM, the $ is used as a terminator (typically) when calling an
  interrupt service routine.  If you are doing assembly calls in a section
  of code you need only
  
  #if DOS
  #undef EOS
  #define EOS '$'
  #endif
  for ( this=that; someloop<ArraySize && etc; someloop++)
    if (someloop=ArraySize-1){
      (*array)[someloop]=EOS;
      CallToAssembly(*array);
    }else
      DoSomethingElse((*array)[someloop]);

  #if DOS
  #undef EOS
  #define EOS '\0'
  #endif

  Typically, one could even replace '$' and '\0' further with
  DOS_CPM_TERMINATOR and UNIX_DOS_C_CALL_TERMINATOR.  So, while you as
  a Unix or Dos or whatever programmer might not care about the others, it
  allows a level of abstraction that facilitates portability and
  maintainability.


  Mind you, I might like shorter labels, but one get's the idea.

>
>Other cases occur where someone makes #defines for error strings
>that are used only once:
>
>#define	FOO_BAR_ERROR	"foo bar error"
>#define UNDEF_BAZ_ERR	"undef baz err"
>
>I cringe when I come across code like this.  Needlessly removing objects
>a level is distracting and gains nothing.

  It seems here that if FOO_BAR_ERROR is something along the lines
  of 

  #define DATACOM_NOT_INIT "Datacomm was not initialized"

  might be usefull.  One could then modify this like so:

  #if MSDOS
  #define DATACOM_NOT_INIT "Execute datacomm.exe and restart the program"
  #elif  SYSV
  #define DATACOM_NOT_INIT "Contact you system administrator for datacomm startup"
  #elif BTOS
  #define DATACOM_NOT_INIT "Master Cluster datacomm not initialized"
  #else
  #define DATACOM_NOT_INIT "Datacomm is not initailized"
  #endif


  Now, which is more 1)Cost effective 2)Maintainable ergo 
  3)Good programming style? To go through and have to change this message
  every time you port the code, or allow for changes without having to
  modify the code beyond considering operational differences because
  your macros cover most of the bases?

  In fact, there are few instances in which text strings and constants
  should not be removed to a macro level (IMHO, mind you, IMHO).  
  To do so means that the programmer will need to know where the pertinent
  substitutions are located, and the programmer should insure that all
  labels are clear in their intent.  IMHO this just means that good
  programming requires more work up front and less work later on, but that
  is the tradeoff between development and maintenance.  It also impacts on
  the reusability of code.  Pay me now or pay me later.

>
>Rich
>-- 
>skrenta@blekko.commodore.com

cbp

cbp@icc.com

henry@zoo.toronto.edu (Henry Spencer) (08/20/90)

In article <1990Aug20.000227.12867@icc.com> cbp@icc.com (Chris Preston) writes:
>>In many cases the object itself becomes familiar enough that it's
>>instantly recognized.  '\0' is one such object.  If I saw in your
>>code
>>
>>	*p = EOS;
>>
>>I'd have to run off to your .h files to find the definition of EOS.
>
>  Perhaps a comment in an appropriate place might alleviate this.

Comments are not a substitute for using familiar practices instead of
unfamiliar ones.  Familiar ones should be preferred unless there is
a *substantial* advantage to be had.  I don't see one here.
-- 
Committees do harm merely by existing. | Henry Spencer at U of Toronto Zoology
                       -Freeman Dyson  |  henry@zoo.toronto.edu   utzoo!henry

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (08/20/90)

In article <1990Aug20.000227.12867@icc.com>, cbp@icc.com (Chris Preston) writes:
(quoting a quote)
> >Other cases occur where someone makes #defines for error strings
> >that are used only once:

> >#define	FOO_BAR_ERROR	"foo bar error"
> >#define UNDEF_BAZ_ERR	"undef baz err"
> >
> >I cringe when I come across code like this.  Needlessly removing objects
> >a level is distracting and gains nothing.

and then defends this, where there are conditional definitions.
He suggests
>   #if MSDOS
>   #define DATACOM_NOT_INIT "Execute datacomm.exe and restart the program"
>   #elif  SYSV
>   #define DATACOM_NOT_INIT "Contact you system administrator for datacomm startup"
>   #elif BTOS
>   #define DATACOM_NOT_INIT "Master Cluster datacomm not initialized"
>   #else
>   #define DATACOM_NOT_INIT "Datacomm is not initailized"
>   #endif

as an example of a Good Thing.  I cringe when I see code like this too.
For why?  Internationalisation, _that's_ for why.

>   It also impacts on the reusability of code.  Pay me now or pay me later.

Considering the large negative impact on internationalisation of having
fixed strings in the program, may we _bill_ him, I wonder?

A very simple way of making a "resource file" in UNIX is this:

cat >resource.awk <<'end_of_file.'
BEGIN	{ pos = 0
	  max = 0
	}
	{ print "#define", $1, (pos + length($1) + 1) "L"
	  pos += length + 1	# for MS-DOS, use + 2
	  l = length - length($1) - 1
	  if (l > max) max = l
	  filename = FILENAME
	}
END	{ print "#define res__file \"" filename "\""
	  print "#define res__max  " max
	}
end_of_file.
cat >resource.c <<'end_of_file.'
#include <stdio.h>
#include "resource.h"

char *rescpy(dst, dstlen, offset)
    char *dst;
    int dstlen;
    long offset;
    {
	FILE *resfile;
	char buffer[res__max+1];
	int ok;

	resfile = fopen(res__file, "r");
	if (!resfile) return NULL;
	ok = fseek(resfile, offset, 0) == 0
	  && fgets(dst, dstlen, resfile) != NULL;
	fclose(resfile);
	return ok ? dst : NULL;
    }

void reserr(offset)
    long offset;
    {
	char buffer[512];
	if (rescpy(buffer, sizeof buffer, offset))
	    fprintf(stderr, "%s", buffer);
	else
	    fprintf(stderr, "Unknown error (%ldL)\n", offset);
    }

end_of_file.

This takes a resource file made up of lines
	<message name> <TAB> <message text>
If you do
	awk -f resource.awk resourcefile >resource.h
and then
	cc -c resource.c
you get a header file defining the <message name>s to be the
appropriate offsets in the resource file, and then
	rescpy(buffer, sizeof buffer, MessageName)
with arguments rather like fgets() will give you a copy of the
message, and
	reserr(MessageName)
will write the message to stderr.

The bottom line is that you can just make a whole bunch of files
	resource.uk
	resource.us
	resource.fr
	resource.dk
and so on, then
	awk -f resource.awk resource.$LANG >resource.h
and re'make'ing your program will let you adapt to a different language.

(I used awk here to keep this posting short.  It would be better to make
the header file with a C program so that you could use ftell() to get
exactly the right values to give to fseek().)

Of course, if you are using CMS, or VMS, or SVR4, or something with the
X/Open "nls" routines, you could use those.  Unfortunately, none of these
interfaces is portable.  A crude and limited hack like the one above may
have a (near term) place in writing code portable between these systems.

This code is free.  Free code is worth what you pay for it.
-- 
The taxonomy of Pleistocene equids is in a state of confusion.

ergo@netcom.UUCP (Isaac Rabinovitch) (08/20/90)

In <1990Aug20.073554.9537@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:

>>>In many cases the object itself becomes familiar enough that it's
>>>instantly recognized.  '\0' is one such object.  If I saw in your
>>>code
>>>
>>>	*p = EOS;
>>>
>>>I'd have to run off to your .h files to find the definition of EOS.
>>
>>  Perhaps a comment in an appropriate place might alleviate this.

>Comments are not a substitute for using familiar practices instead of
>unfamiliar ones.  Familiar ones should be preferred unless there is
>a *substantial* advantage to be had.  I don't see one here.

I agree with you in principle, and also in this instance (does anyone
seriously intend to put a comment at every end-of-string comparison?).
The problem is with the concept of "familiar".  This business of
strings always terminating with a null is fundamental to C programming
-- if you don't know that '\0' means "end-of-string" then you simply
don't know how C strings work at all!  (Note that nobody ever uses
an (int) 0 in place of '\0', even though the two are equivalent!)

On the other hand, you can say (and I used to) that using 1 and
0 instead of TRUE and FALSE is a similar "familiar practice", since any
competant C programmer knows that C booleans are just integers.  
In this case it probably makes a big difference that TRUE and FALSE are
ordinary English words, not obscure acronyms.

I recently came up against a similar clash of "familiar concepts" in
C.  People were arguing (was it in this group?) over why programmers
use "i" instead of "i == 0".  I asserted that this shorter expression
usually generated tighter code, at least on stupider compilers.  I
think I might have been right about this 10 years ago, but even if I
was I'd only shown I was out of date in the current state of compiler
writing.  I got one private message from a guy at a certain Big
Software Company who told me that reducing such comparisons was the
first optimization any compiler writer implemented.  True enough, but
what I found especially interesting was all the public and private
flames fired at me by folks who insisted not just that I was wrong
(which, of course, I was) but that the C language was *defined* to
include such a reduction!
-- 

ergo@netcom.uucp			Isaac Rabinovitch
atina!pyramid!apple!netcom!ergo		Silicon Valley, CA
uunet!mimsy!ames!claris!netcom!ergo

Disclaimer:  I am what I am, and that's all what I am!

chip@tct.uucp (Chip Salzenberg) (08/21/90)

According to cbp@icc.com (Chris Preston):
>In article <134@blekko.UUCP> skrenta@blekko.UUCP (Rich Skrenta) writes:
>>*You* like your non-standard name for '\0', but no one else will
>>know what it means, and it's unlikely that it will ever be a Big Win
>>for you (like if we start terminating strings with ^A or something).
>
>Then, it will be a very big win.

Yes, but it will never happen.  I'm sure that Rich just forgot the
smiley.

Remember that '\0'-terminated strings are a part of the C language.
Get rid of them, and you don't have C any more.

It is obvious that most magic numbers should be removed to macro
definitions.  However, '\0' isn't one of them; it will NEVER change.
Not as long as you're programming in C, anyway...
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>

cbp@icc.com (Chris Preston) (08/21/90)

From article <3585@goanna.cs.rmit.oz.au>, by ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe):
> In article <1990Aug20.000227.12867@icc.com>, cbp@icc.com (Chris Preston) writes:
> (quoting a quote)
>> >Other cases occur where someone makes #defines for error strings
>> >that are used only once:
> 
>> >#define	FOO_BAR_ERROR	"foo bar error"
>> >#define UNDEF_BAZ_ERR	"undef baz err"
>> >
>> >I cringe when I come across code like this.  Needlessly removing objects
>> >a level is distracting and gains nothing.
> 
> and then defends this, where there are conditional definitions.
> He suggests
>>   #if MSDOS
>>   #define DATACOM_NOT_INIT "Execute datacomm.exe and restart the program"
>>   #elif  SYSV
>>   #define DATACOM_NOT_INIT "Contact you system administrator for datacomm startup"

and I said etc, etc.

> as an example of a Good Thing.  I cringe when I see code like this too.

  No, an example of separating abstraction through the use of lables.

> For why?  Internationalisation, _that's_ for why.

  Hm, now we go to a different level.  Probably a good point.

>>   It also impacts on the reusability of code.  Pay me now or pay me later.
> 
> Considering the large negative impact on internationalisation of having
> fixed strings in the program, may we _bill_ him, I wonder?

  We is out of context, and no, you may not.

> 
> A very simple way of making a "resource file" in UNIX is this:

  deleted.

> 
> The bottom line is that you can just make a whole bunch of files
> 	resource.uk
> 	resource.us
> 	resource.fr
> 	resource.dk
> and so on, then
> 	awk -f resource.awk resource.$LANG >resource.h
> and re'make'ing your program will let you adapt to a different language.
> 
> (I used awk here to keep this posting short.  It would be better to make
> the header file with a C program so that you could use ftell() to get
> exactly the right values to give to fseek().)

  Sure, and if one does this in System V one could just push a streams module 
  on top of the line discipline and let all applications work in the chosen 
  language.  Quick, neat and available.  But we digress into issues of O/S
  rapidly here.

  At this point someone politely suggests that the newsgroup and its
  O/S independence is worth considering.  
  
 In that spirit, I would like to return to the actual issue (as noted in
 the subject line, though I was guilty of diverging from it ).
 I have been thinking more on the EOS issue, and since 
 it would break lots of things were someone to do this in other than
 special cases (like, breaking all string functions is rude, don't you think?), 
 means that I was wrong in suggestion labeling '\0' in anything other than
 itself is a good idea.  
 
 Retraction is hereby submitted.
  
 Better not to touch that which is so basic to the language itself.  There is no
 clearly important benefit in allowing for a change of such an unlikely nature.

 Basta, finito.

cbp
cbp@icc.com
---------
That is twice in one day --al, don't let it get to you.
---------
Of course, these are opinions.

rmj@tcom.stc.co.uk (Rhodri James) (08/21/90)

In article <3585@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
}In article <1990Aug20.000227.12867@icc.com>, cbp@icc.com (Chris Preston) writes:
}(quoting a quote)
}> >#define	FOO_BAR_ERROR	"foo bar error"
}> >#define UNDEF_BAZ_ERR	"undef baz err"
}> >
}> >I cringe when I come across code like this.  Needlessly removing objects
}> >a level is distracting and gains nothing.
}
}and then defends this, where there are conditional definitions.
}>   #if MSDOS
}>   #define DATACOM_NOT_INIT "Execute datacomm.exe and restart the program"
}>   #elif  SYSV
   [etc]
}as an example of a Good Thing.  I cringe when I see code like this too.
}For why?  Internationalisation, _that's_ for why.

I cringe when I see this (unwords like "internationalisation", I mean).
I take it that by that you mean converting strings in code to foreign
languages ("an act of making something international", as if it did any
such thing). Also I fail to see your point. Surely such #ifdef switching
as above is more efficient, simpler to maintain and more legible than
the scrabbling about with resource files you prefer? I know which I
would rather do of running pre-preprocessing or just compiling with
"-DFRENCH".

}>   It also impacts on the reusability of code.  Pay me now or pay me later.
}
}Considering the large negative impact on internationalisation of having
}fixed strings in the program, may we _bill_ him, I wonder?

Demonstrate to me a negative impact on internationalisation (ugh) and I
might believe you. Any negative impact will do, I'm not too choosy.
-- 
* Windsinger                 * "Nothing is forgotten..."
* rmj@islay.tcom.stc.co.uk   *                    Mike Whitaker
*     or (occasionally)      * "...except sometimes the words"
* rmj10@phx.cam.ac.uk        *                    Phil Allcock

chris@mimsy.umd.edu (Chris Torek) (08/22/90)

>In article <3585@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au
(Richard A. O'Keefe) recommends against `#define'ing error strings
and recommends instead, e.g., reading them from a file:
>>For why?  Internationalisation, _that's_ for why.

In article <1881@jura.tcom.stc.co.uk> rmj@tcom.stc.co.uk (Rhodri James)
writes:
>I cringe when I see this (unwords like "internationalisation", I mean).

Well, I am not particularly enamoured of polysyllabic neologisms
applied epideictically myself. :-)  But I evagate:

>I take it that by that you mean converting strings in code to foreign
>languages ("an act of making something international", as if it did any
>such thing). Also I fail to see your point. Surely such #ifdef switching
>as above is more efficient, simpler to maintain and more legible than
>the scrabbling about with resource files you prefer?

Efficient?  Probably so---but we are talking about an error handler
here.  (`My code handles 100,000 errors per second!  Of course it
only handles 10 non-errors per second....')  Simpler to maintain?
Perhaps.  More legible?  Not really; maybe even not at all:

>I know which I would rather do of running pre-preprocessing or just
>compiling with "-DFRENCH".

I do not understand why these are listed as the alternatives (what
`running pre-processing'?).  But given modern networks and systems,
it is not only possible, it is even likely that the same machine
will be used simultaneously from Japan, the USA, France, and Germany,
and the same utility (a single binary compiled in the UK) may have
to produce the same error message in four different languages, all
at the same time, with one of them in a 16-bit character set.

This is rather difficult to accomodate cleanly in the source---
particularly if one is called upon to add a new language every day
(for a week or two, then every few days, and eventually only one
a year or so).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

cuuee@warwick.ac.uk (Sean Legassick) (08/24/90)

In article <1990Aug20.000227.12867@icc.com> cbp@icc.com (Chris Preston) writes:
[quoting a quote]
>>*You* like your non-standard name for '\0', but no one else will
>>know what it means, and it's unlikely that it will ever be a Big Win
>>for you (like if we start terminating strings with ^A or something).
>
>  Then, it will be a very big win.  Using two characters would break
>  much more software than would changing the terminator to a single
>  different letter.  In the case of doing a sprinkling of assembly
>  on DOS or CPM, the $ is used as a terminator (typically) when calling an
>  interrupt service routine.  If you are doing assembly calls in a section
>  of code you need only
>  
[code omitted]
>
>  Typically, one could even replace '$' and '\0' further with
>  DOS_CPM_TERMINATOR and UNIX_DOS_C_CALL_TERMINATOR.  So, while you as
>  a Unix or Dos or whatever programmer might not care about the others, it
>  allows a level of abstraction that facilitates portability and
>  maintainability.
>
>
>  Mind you, I might like shorter labels, but one get's the idea.
>
	Very clever, but it hardly solves the problem of different string
representations - consider Pascal. It has not terminator, strings start with
a count. No amount of #defining will solve that.

---------------------------------------------------------------------------
Sean Legassick,       cuuee@uk.ac.warwick.cu	"Man, I'm so hip I find it
  Computing Services	  (the walking 	           difficult to see over
    University of Warwick   C obfuscator!)	     my pelvis" - D Adams