[comp.lang.c] A Deficiency of the C Preprocessor

cramer@kontron.UUCP (Clayton Cramer) (12/18/86)

I've got a complaint about the C preprocessor -- I doesn't support a
repetition for initializing data structures.

We are developing programs where an array of structures exists.

	#define BRKPTCOUNT	5
	struct .... FooBar[BRKPTCOUNT] = {....};

Everytime we change BRKPTCOUNT, we have to change the initialization data
for FooBar; if we give extra initialization data, we get complaints from the
compiler; if we don't give enough data, the rest of the structure isn't
initialized.

We've worked around this annoyance by defining a function that initializes
the FooBar, but this takes time and code to do at runtime something that
should be doable at compile time.  Something equivalent to the assembler
directive DUP would be ideal, since it would allow us to replace the
lines above with:

	#define BRKPTCOUNT	5
	struct .... FooBar[] = {5 DUP {....}};

and scrap the initialization code.

We COULD build our own preprocessor to take care of this, but a general
solution, perhaps as part of some future version of the ANSI C spec would 
be better.

Clayton E. Cramer

"You cannot bring about prosperity by discouraging thrift.  You cannot
 strengthen the weak by weakening the strong.  You cannot help the wage
 earner by pulling down the wage payer.  You cannot further the brother-
 hood of man by encouraging class hatred.  You cannot keep of out of
 trouble by spending more than you earn.  You cannot build character and
 courage by taking away man's initiative and independence.  You cannot
 help men permanently by doing for them what they could and should do
 for themselves."  -- Abraham Lincoln

braner@batcomputer.tn.cornell.edu (braner) (12/19/86)

In article <1259@kontron.UUCP> cramer@kontron.UUCP (Clayton Cramer) writes:
>I've got a complaint about the C preprocessor -- I doesn't support a
>repetition for initializing data structures.
> ...
>We've worked around this annoyance by defining a function that initializes
>the FooBar, but this takes time and code to do at runtime something that
>should be doable at compile time. ...

I would like, if not that, at least an acceptance by the preprocessor
of more parameters than required.  As for compile vs. run time
initialization of arrays:  A compiler I use creates code for all the
initializations in the program, code that runs when you invoke the program
and copies all the initial data from the code to the variable-data areas.
(To sound technical: from the data (or code) segment to the bss segment.)
This means that during the execution of the program, TWICE the memory is
needed to hold the data.  This is necessary in environments where code
is not to be modified (e.g. ROM), but in other environments is wasteful.

Even worse, when an array is initialized, this compiler generates a line
of code to initialize each entry, rather than an image of the array and
looping code. This approximately DOUBLES the length of the initialization
section of the code (and the total memory use is now TRIPLE what it could
be...).  Is this typical for C compilers?  Could you compiler-writers
avoid this in the future, please?

- Moshe Braner

chris@mimsy.UUCP (Chris Torek) (12/20/86)

>In article <1259@kontron.UUCP> cramer@kontron.UUCP (Clayton Cramer) writes:
>>I've got a complaint about the C preprocessor -- I doesn't support a
>>repetition for initializing data structures.

Why is this a complaint about the preprocessor?  The preprocessor
knows nothing about data structures.  (I do think it might be neat
to have loop constructs in the preprocessor.  E.g., to unroll a
loop, instead of writing

	*p++ = 0; *p++ = 1; *p++ = 2; *p++ = 3;
	*p++ = 4; *p++ = 5; *p++ = 6; *p++ = 7;

one could write

	#for (i = 0; i < 8; i++) {
		*p++ = i;
	#}

A fully programmable preprocessor would at least make a fun toy. :-)
[Of course, you can always write your own preprocessor.])

In article <1888@batcomputer.tn.cornell.edu>
braner@batcomputer.tn.cornell.edu (braner) writes:
>I would like, if not that, at least an acceptance by the preprocessor
>of more parameters than required.

I find this even more confusing.  The only `parameters' in the
preprocessor are those given to macros.  A preprocessor that silently
ignored extra arguments to a macro would be quite annoying.

>As for compile vs. run time initialization of arrays:  A compiler I
>use creates code for all the initializations in the program ...
>Even worse, when an array is initialized, this compiler generates a line
>of code to initialize each entry, rather than an image of the array and
>looping code.

That sounds like a pretty poor compiler to me.  Whose is it, that
we may all avoid buying it?
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu

woerz@iaoobelix.UUCP (12/22/86)

> I've got a complaint about the C preprocessor -- I doesn't support a
> repetition for initializing data structures.
>
> We are developing programs where an array of structures exists.
>
>         #define BRKPTCOUNT      5
>         struct .... FooBar[BRKPTCOUNT] = {....};
>
> Everytime we change BRKPTCOUNT, we have to change the initialization data
> for FooBar; if we give extra initialization data, we get complaints from the
> compiler; if we don't give enough data, the rest of the structure isn't
> initialized.

Why don't you write your structures and defines like this:

    #define BRKPTCOUNT  (sizeof (FooBar)/sizeof (FooBar[0]))
    struct ... FooBar [] = { ... } ;

Then your array will be maid as large as needed to fit your data.
The size of the array (defined by BRKPTCOUNT) will be computed during
compile time, since sizeof is a compile time function and the whole
expression is constant.

> ...
------------------------------------------------------------------------------

Dieter Woerz
Fraunhofer Institut fuer Arbeitswirtschaft und Organisation
Holzgartenstrasse 17
D-7000 Stuttgart 1
W-Germany

BITNET: ...unido.bitnet!iaoobel.uucp!woerz
UUCP:   ...seismo!unido!iaoobel!woerz

wagner@iaoobelix.UUCP (12/22/86)

> > I've got a complaint about the C preprocessor -- I doesn't support a
> > repetition for initializing data structures.
> >
> > We are developing programs where an array of structures exists.
> >
> >         #define BRKPTCOUNT      5
> >         struct .... FooBar[BRKPTCOUNT] = {....};
> >
> > Everytime we change BRKPTCOUNT, we have to change the initialization data
> > for FooBar; if we give extra initialization data, we get complaints from the
> > compiler; if we don't give enough data, the rest of the structure isn't
> > initialized.
> 
> Why don't you write your structures and defines like this:
> 
>     #define BRKPTCOUNT  (sizeof (FooBar)/sizeof (FooBar[0]))
>     struct ... FooBar [] = { ... } ;
> 
> Then your array will be maid as large as needed to fit your data.
> The size of the array (defined by BRKPTCOUNT) will be computed during
> compile time, since sizeof is a compile time function and the whole
> expression is constant.
> 

I think, it is still a problem if you want the data structure  to
be  initialized  with  exactly  `n' identical elements (well, not
idential: with 'n' elements containing the  same  values).  Then,
cpp  is  really lacking a means of introducing repetitions of the
kind mentioned above. Determining the actual number  of  elements
in  that  array is no problem, as Dieter has already pointed out.
Yet, my solution to your problem would be the following (it is  a
quick hack, I know...):

>>file foo.c

	# define BRKPTCOUNT 5
	# define FooBar_INIT { ... }
	struct s_frob FooBar[] = {
	# include "FooBar-init.h"
		};
	...

Your Makefile will then contain some instructions for generating
FooBar-init.h, finally containing `n' times the appropriate symbol
FooBar_INIT, separated by commas.

Anyway, if you don't like this solution (I don't like it, too), try
use the m4 macro preprocessor instead of cpp. M4 allows calling UNIX
programs from within the preprocessor. Example:

>>file rep.c
	# include <stdio.h>

	main(argc,argv)
	int argc;
	char **argv;
	{
	   int i;
	
	   if (argc == 3)
	      for (i=atoi(argv[1]); i>0; i--)
		 printf("%s%s\n", argv[2], i==1 ? "" : ",");
	}

>>file foo.c (containing the macro calls)
	...
	define(BRKPTCOUNT, 5)
	define(ITEM, foo)
	syscmd(rep BRKPTCOUNT ITEM)
	...

This will insert BRKPTCOUNT times the string specified by ITEM into
your source file... (basically the same procedure as above).

I hope this is of use,

Juergen Wagner,			(USENET)   ...!unido!iaoobel!wagner
					        wagner@iaoobel.UUCP
	 			Fraunhofer Institute IAO, Stuttgart

greg@utcsri.UUCP (Gregory Smith) (12/23/86)

>>In article <1259@kontron.UUCP> cramer@kontron.UUCP (Clayton Cramer) writes:
>>>I've got a complaint about the C preprocessor -- I doesn't support a
>>>repetition for initializing data structures.
>
In article <4863@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>Why is this a complaint about the preprocessor?  The preprocessor
>knows nothing about data structures.

Yes, but it could still make repeated text, which could be used to
create repeated data structures, code, or what have you. You
have missed Clayton's point.

>In article <1888@batcomputer.tn.cornell.edu>
>braner@batcomputer.tn.cornell.edu (braner) writes:
>>As for compile vs. run time initialization of arrays:  A compiler I
>>use creates code for all the initializations in the program ...
>>Even worse, when an array is initialized, this compiler generates a line
>>of code to initialize each entry, rather than an image of the array and
>>looping code.
>
[Chris again].
>That sounds like a pretty poor compiler to me.  Whose is it, that
>we may all avoid buying it?

I have never seen a C compiler that does this, but I know of another
supposedly powerful language compiler that does. And of course there
is P*sc*l, which not only does this but forces the programmer to write
out the code too [i.e. there are no compile-time inits].

It isn't really that bad on a virtual memory machine, since the initial-
ization code is only used once, and will be quickly paged out forever.
Hopefully the link environment is such that this code is
all bunched together.

If I say:
foo(){
	static int bar=0;
	...
then 'bar' must be set to zero sometime before the first call to 'foo', and
must *not* be set to zero on subsequent calls to foo. On braner's compiler,
does this work, and if so, how? Does the compiler put 'CLR bar' into a
separate code area which is executed at startup? This sounds like more
trouble than real initialization...
-- 
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg
Have vAX, will hack...

aeusemrs@csun.UUCP (Mike Stump) (12/23/86)

In article <1259@kontron.UUCP> cramer@kontron.UUCP (Clayton Cramer) writes:
>I've got a complaint about the C preprocessor -- I doesn't support a
>repetition for initializing data structures.
[ edited for space ]
>Clayton E. Cramer

Clayton,  if you are running Unix System V, all of your problems
are solved;  there is another preprocessor called 'm4' that will
do what you want, and then some. (This might also be true of other systems.)

But if you are not running System V, then you will find that you
will probably have to continue to do what you have been doing, or
write a simple (or complex :-)) preprocessor to do what you want.

						Mike Stump

tps@sdchem.UUCP (Tom Stockfisch) (12/24/86)

In article <6700001@iaoobelix.UUCP> woerz@iaoobelix.UUCP writes:
>> We are developing programs where an array of structures exists.
>>
>>         #define BRKPTCOUNT      5
>>         struct .... FooBar[BRKPTCOUNT] = {....};
>>
>> Everytime we change BRKPTCOUNT, we have to change the initialization data
>> for FooBar...

>Why don't you write your structures and defines like this:
>
>    #define BRKPTCOUNT  (sizeof (FooBar)/sizeof (FooBar[0]))
>    struct ... FooBar [] = { ... } ;

I think what he wants is to choose
brkptcount and then have that many
(identical?) units put between the {}'s
to initialize FooBar.  Also note that
your solution does not work if
BRKPTCOUNT is to be used in a different
file, since the other file won't be able
to specify the array size in it's decl
of FooBar.  You can change "#define" to
"int", but then you no longer have a
constant.  I think its impossible to
determine the size of an array in a
different module, unless that module
communicates the size explicitly.

|| Tom Stockfisch, UCSD Chemistry	tps%chem@sdcsvax.UCSD

cramer@kontron.UUCP (Clayton Cramer) (12/30/86)

> > I've got a complaint about the C preprocessor -- I doesn't support a
> > repetition for initializing data structures.
> >
> > We are developing programs where an array of structures exists.
> >
> >         #define BRKPTCOUNT      5
> >         struct .... FooBar[BRKPTCOUNT] = {....};
> >
> > Everytime we change BRKPTCOUNT, we have to change the initialization data
> > for FooBar; if we give extra initialization data, we get complaints from the
> > compiler; if we don't give enough data, the rest of the structure isn't
> > initialized.
> 
> Why don't you write your structures and defines like this:
> 
>     #define BRKPTCOUNT  (sizeof (FooBar)/sizeof (FooBar[0]))
>     struct ... FooBar [] = { ... } ;
> 
> Then your array will be maid as large as needed to fit your data.
> The size of the array (defined by BRKPTCOUNT) will be computed during
> compile time, since sizeof is a compile time function and the whole
> expression is constant.
> 

The ARRAY ends up big enough -- but only the number of initializing values
are actually inserted into the array (at least under BSD 4.2).

Clayton E. Cramer

"You cannot bring about prosperity by discouraging thrift.  You cannot
 strengthen the weak by weakening the strong.  You cannot help the wage
 earner by pulling down the wage payer.  You cannot further the brother-
 hood of man by encouraging class hatred.  You cannot keep of out of
 trouble by spending more than you earn.  You cannot build character and
 courage by taking away man's initiative and independence.  You cannot
 help men permanently by doing for them what they could and should do
 for themselves."  -- Abraham Lincoln

knudsen@ihwpt.UUCP (mike knudsen) (01/06/87)

> >>As for compile vs. run time initialization of arrays:  A compiler I
> >>use creates code for all the initializations in the program ...
> >>Even worse, when an array is initialized, this compiler generates a line
> >>of code to initialize each entry, rather than an image of the array and
> >>looping code.
> >That sounds like a pretty poor compiler to me.  Whose is it, that
> >we may all avoid buying it?
> 
> I have never seen a C compiler that does this, but I know of another
> supposedly powerful language compiler that does. And of course there
> If I say:
> foo(){
> 	static int bar=0;
> 	...
> then 'bar' must be set to zero sometime before the first call to 'foo', and
> must *not* be set to zero on subsequent calls to foo. On braner's compiler,
> does this work, and if so, how? Does the compiler put 'CLR bar' into a
> separate code area which is executed at startup? This sounds like more
> trouble than real initialization...

How else to init this?

He may be talking about the OS9 Level I C compiler from Microware,
which I use all the time at home.  It does indeed go thru
agonizing space and time-consuming initializations on startup.
The reason for this is that OS9 C is required to produce
re-entrant, sharable object programs.  That is,
after I've been running such a program for a while, another
process or user can start up that same program.
He will use the same copy of pure code in RAM as I've been,
but he has to get his own data area initialized from scratch.

Unforch, this C doesn't have any "read-only" or "ROMable" declarations
for initialized data that you promise not to alter while running.

Since the program I'm writing will never be shared, I'd love to
get around this waste, but ....

-- 
Mike J Knudsen    ...ihnp4!ihwpt!knudsen
"It's like trying to get to sleep at the Intergalactic
Spaceport Hotel -- waiting for the being in the room above
to drop the Nth shoe, and you don't even know what N is."