[comp.lang.c] portability/maintenance

bevan@cs.man.ac.uk (Stephen J Bevan) (05/30/90)

Some months ago, I think someone asked a question about tips on
writing portable programs.  Numerous people answered and a summary
was produced.

One suggestion was that for large projects (don't ask me to define
large) a set of standards be drawn up before you start i.e. what
the indentation style is, where the comments go etc.  These were
the sort of things I expected to see.

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) :-

#define PUBLIC
#define INOUT
#define IN
#define PRIVATE static
#define FORWARD extern

These would then be used in .c files to make functions look like :-

PUBLIC void some_function(anInt, aChar)
  INOUT int *anInt;
  IN char aChar;
{
  FORWARD another_function();
  ...
}

PRIVATE void another_function(aParam)
  OUT int *aParam;
{
  ...
}

What I'd like to know is do people acutally use this, and would
they mind having to maintain code that was written this way?

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.

As a final point, if you think its an ok idea, do you still think
its ok if the macros were changed to lower case?  (I guess the
answer to this will be no, its just that I really hate UPPER CASE)

Stephen J. Bevan

bevan@cs.man.ac.uk

mike@hpfcso.HP.COM (Mike McNelly) (05/31/90)

> ...
> 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) :-
> 
> #define PUBLIC
> #define INOUT
> #define IN
> #define PRIVATE static
> #define FORWARD extern
> 
> These would then be used in .c files to make functions look like :-
> 
> PUBLIC void some_function(anInt, aChar)
  > INOUT int *anInt;
  > IN char aChar;
> {
  > FORWARD another_function();
  > ...
> }
> 
> PRIVATE void another_function(aParam)
  > OUT int *aParam;
> {
  > ...
> }
> 
> What I'd like to know is do people acutally use this, and would
> they mind having to maintain code that was written this way?

> 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.
> 
> As a final point, if you think its an ok idea, do you still think
> its ok if the macros were changed to lower case?  (I guess the
> answer to this will be no, its just that I really hate UPPER CASE)
> 
> Stephen J. Bevan

This is all religion so don't be too surprised if you get diverse,
argumentative responses.  However, here's a personal view.

We've used

# ifdef DEBUGGING
#	define LOCAL
# else	/* DEBUGGING */
#	define LOCAL static
# endif	/* DEBUGGING */

for years as a construct in our headers because it simplifies use of the
symbolic debugger during development (static vars normally don't have
full information in the a.out file).

Personally I don't get too excited about dummy defines one way or the
other but they do seem to be an attempt to provide useful information.
My preference is to make all macros uppercase just so I know that
they're macros and not functions (it does make a difference, of course).
Some of my collegues like mixed case identifiers as a byzantine method
of encoding all sorts of information (much like your dummy macros above)
but this just seems to get in the way of my poor typing skills.

Mike McNelly
mike%hpfcla@hplabs.hp.com

robert@isgtec.UUCP (Robert A. Osborne) (06/01/90)

bevan@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.

Rob.
-- 
Robert A. Osborne   ...uunet!utai!lsuc!isgtec!robert or robert@isgtec.uucp

logan@inpnms.VSE.COM (James L. Logan) (06/05/90)

In article <BEVAN.90May29182035@panda.cs.man.ac.uk>
bevan@cs.man.ac.uk (Stephen J Bevan) writes:  
# One suggestion was that for large projects (don't ask me to define
# large) a set of standards be drawn up before you start i.e. what
# the indentation style is, where the comments go etc.  These were
# the sort of things I expected to see.

Fine, unless those who decide on the style do not fit in to one of
the mainstream styles.  (Styles were already discussed in another
c.l.c war flamefest.) 

What happens when the people who chose the style leave and no one
knows why they're coding in a style they hate a couple of years
down the road?

# 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) :-
# 
# #define PUBLIC
# #define INOUT
# #define IN
# #define PRIVATE static
# #define FORWARD extern

Please don't do this.  See below.

# What I'd like to know is do people acutally use this, and would
# they mind having to maintain code that was written this way?

Yes, people do mind.  In fact, it's completely annoying.

# 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.

They will.  Please don't.

As an example, the psuedo keywords "EXPORT", "IMPORT", and
"PRIVATE" cannot be referenced in C programming books, manuals,
etc., whereas the use of static and non-static variables and
functions are described in definitive C books.  They also
condition the beginner programmers to look for PRIVATE/EXPORT
keywords in 3rd party sources when problems arise.  (As in a 3rd
part database library for instance.) They simply won't find them,
and will find it difficult to adjust.

The psuedo keyword "EXPORT" is misleading because it is not
defined in the C syntax, thus it appears as though it can be
applied to any function or variable.  This is not the case; take
this trivial example for instance:


#include <stdio.h>
#include <unistd.h>

int	file_exists(path)
	char	*path;
{
	int
		retval;

	retval = access(path, F_OK);
	return (retval? 0: 1);
}

char	*mkfullname(path, filename)
	char	*path, *filename;
{
	EXPORT char
		buffer[20];

	sprintf(buffer, "%s/%s", path, filename);
	return buffer;
}

int	main(argc, argv)
	int	argc;
	char	**argv;
{
	char
		*fullpath;

	fullpath = mkfullname(argv[1], argv[2]);

	if (file_exists(fullpath)) {
		printf("You can read '%s'\n", fullpath);
		exit(0);
	} else {
		printf("Sorry, can't read '%s'\n", fullpath);
		exit(1);
	}
	/*NOTREACHED*/
}


Compile it and run it with one argument being a directory and the
second argument being a filename.  Can you tell me why the
filename prints out as garbage?  Beginning to intermediate C
programmers will try things in their code like I have in my
example and will be unable to debug the program.  Can they use a
C manual to figure it out?  Can they use the standards document
to figure it out?  They will have to view the header file to
figure out what it all means.

We need to make our programming environments as efficient and
problem-free as possible, not pretty the C syntax up to the point
where good C programmers (like a good but expensive consultant)
need time to get up to speed in order to understand the code.   

-- 
James Logan                       UUCP: uunet!inpnms!logan
Data General Telecommunications   Inet: logan@rockville.dg.com
(301) 590-3198

paulh@cognos.UUCP (Paul Hays) (06/05/90)

Attempts to improve C by introducing dummy identifiers are fun, but
they never seem to really improve the language much, IMO.
Instead, I subscribe to the well-known notion that the creativity
of programmers should be curtailed wherever possible. We
should direct our attention to the costly issues of sound
design and thorough documentation. (Duck! Who threw that brick?)

Making a local dialect detracts from one of the main advantages
of C: portability of programming skills. K & R built what has
proved to be a language with wide applicability. Now we have
struggled through years of standard-building to arrive at a
useable portable C. Let's use the standard language.

I've frequently had the, er, opportunity of maintaining huge
applications made with dozens of header files. Such implementations
typically incorporate the 'creative' language ideas of several
previous authors with varying degrees of skill. Many have usually
tried to codify the sort of local standard you have described; these
'standards' always seem to come and go along with the latest manager.
(Yeah, I'm a technical manager: I know whereof I speak.)

How often does the maintenance programmer sit wondering what header
file defines some obscure identifier and whether the current bug
results from its misuse? And how often is the programmer who adds a
feature to a product aware of the subtle implications of the local
standard?

K.I.S.S.!


[The opinions expressed here are mine, not necessarily the company's.]

-- 
Paul Hays                Cognos Incorporated     S-mail: P.O. Box 9707
Voice: (613) 738-1338 ext 3804                           3755 Riverside Drive 
  FAX: (613) 738-0002                                    Ottawa, Ontario 
 uucp: uunet!mitel!sce!cognos!paulh                      CANADA  K1G 3Z4

cseko@stsci.EDU (Andrew Cseko Jr.) (06/07/90)

From article <470@isgtec.UUCP>, by robert@isgtec.UUCP (Robert A. Osborne):
> bevan@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@stsci.edu

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