portability/maintenance

Andrew Cseko Jr. cseko at stsci.EDU
Fri Jun 8 00:08:00 AEST 1990


>From article <470 at isgtec.UUCP>, by robert at isgtec.UUCP (Robert A. Osborne):
> bevan at cs.man.ac.uk (Stephen J Bevan) writes:
>>Another suggestion, however, was to use dummy macros to help make
>>the type and purpose of parameters and functions stand out.  For
>>example, you would have a header file containing the following
>>sort of definitions (the rest of this is in K&R I C, I haven't
>>really got into the swing of ANSI C yet) :-
> The biggest problem with these macros is that they are conventions, not
> syntactical necessities.   Therefore they can be wrong in which case
> they are worse (far worse) than vanilla C.   Another problem is that
> they try and hide language functionality;  I know what a static function
> declaration *IS*;  when I see PRIVATE or local or some such I immediately
> have to look for what it *IS*.   If you can write C code cleanly
> in legible fashion (like I can :-), these macros just get in the way;
> if you can't write code cleanly the greatest macro package in the world
> isn't going to help.
> 
>>What I'd like to know is do people actually use this, and would
>>they mind having to maintain code that was written this way?
> I would probably pass it through sed to get rid of these macros.
> I would HATE to maintain this style of code.
> 
>>I've got to admit I kind of like the idea, but if people are going
>>to bitch about the code if its written in this style, then I'd
>>rather not use it.
> The problem is (as we have seen before in this group) that everybody
> has their own "favourite macros" and hates any other macro set.
> It's best not to use them at all.


In an issue as "religous" as this the burden of correct implementation really
falls on the implementor.  My own concerns would be that the person neither
go "overboard" or "underboard".  By "overboard" I mean they don't use a MACRO 
to document something that is all ready obvious, for instance 
'#define PTR_OF(a)    &(a)'.  In the above example the difference between 
'#define INOUT' and a comment like '/* IN/OUT */' is not clear to me.
And "underboard" means that if you create a 
macros to document code then use them consistently throughout the program
and not just when you 'feel like it'.

In my own development I do use macros to hide code that 1) I do not want to
see once its implemented and 2) do not want to hand type every place I need it.
My prime example is the implemenation of a vector where the type can be float,
int, unsigned short etc.  I have two types COORD and INDEX defined something
like this:

typedef struct
	{
	.
	.
	.
	struct
		{
		U_SHORT ndims;
		float   val[4];
		} public;
	.
	.
	.
	} COORD;

typedef struct
	{
	.
	.
	.
	struct
		{
		unsigned short ndims;
		int val[4];
		} public;
	.
	.
	.
	} INDEX;

I wanted to be able to reference both val arrays without having to always type
'public.val[ i ]'.  And from a philosophical perspective I wanted to 
communicate something like "get/set the i'th dimension of the vector".  My
solution was the following macros

#define get_dim( P, i )      (P)->public.val[ i ]
#define set_dim( P, i, v )   (P)->public.val[ i ] = v

which makes them look like overdefined function in object oriented languages.
They work for any type (of course, only if the structure is defined the same 
way) and the compiler will do proper type conversion of 'v' to the type of
the val[] array.

This was my first pass.  I then realized that without changing any code
I've already written that used these macros I could include debug checks. I 
wanted to verify that 1) index i was less than the dimensionality of the
vector, 2) if I was 'getting' the value - it had already been set somewhere
else and 3) at run-time be able to turn off the debugging.
My macros then became something like the following.

#define get_dim( P, i ) \
       if (debug_level > 50) \
	{ \
	... code to check i < ndims .. \
        ... code to check value already set ... \
        } \
       (P)->public.val[ i ] 

#define set_dim( P, i, v ) \
       if (debug_level > 50) \
	{ \
	... code to check i < ndims .. \
        } \
       (P)->public.val[ i ] = v 

I also wanted to exclude all the debugging code from the production version 
of the executable.  My macros definitions became

#if DEBUGGING
#define get_dim( P, i ) \
       if (debug_level > 50) \
	{ \
	... code to check i < ndims .. \
        ... code to check value already set ... \
        } \
       (P)->public.val[ i ] 
#else
#define get_dim( P, i )      (P)->public.val[ i ]
#endif

#if DEBUGGING
#define set_dim( P, i, v ) \
       if (debug_level > 50) \
	{ \
	... code to check i < ndims .. \
        } \
       (P)->public.val[ i ] = v 
#else
#define set_dim( P, i, v )   (P)->public.val[ i ] = v
#endif


I'm curious about anybody elses experience in using CPP this way?

andrew
cseko at stsci.edu

If 'all the world is a stage' then whose the audience? - me, myself & I



More information about the Comp.lang.c mailing list