ANSI/Non-ANIS Function Declaration Macros

Martin Weitzel martin at mwtech.UUCP
Sat Dec 16 03:16:30 AEST 1989


In article <4603 at itivax.iti.org> scs at itivax.iti.org (Steve Simmons) writes:
>
>Currently I'm writing code that must compile with and without ANSI
>C features.  Ideally this could be done with no slgging the code
>with lots of #ifdef constructs like
>
>#ifdef __STDC__
>int	*foo( int const a )
>#else
>int	*foo( a )
>int	a ;
>#endif
>{
>	func body
>}
>
>While this works, it's got a weakness.  In having two separate declarations,
>one can over time let them get out of sync.  It's also a pain to write.

It's a pain to write, true, but the chance of getting 'out-of-sync' is
small, because the two declarations are near by each other.

>Has anybody come up with a way of doing this so that I write the declarations
>once and once only?  Bizarre constructs considered within limits.

If your concern isn't to convert any arbitrary C-source from K&R-Style
to prototypes, but only two write "compatible" code yourself, it's
easy to stick to some formatting conventions and do the conversions with
a tool like 'awk' or 'lex' ('sed' might not be sufficient ...).

To show an appropiate formatting convention, I expand the example a
little:
	/* ... only for decoration ... */
	typedef (*FPI)();

	/* ... the real stuff ... */
	int *foo
	(
		const int a,	/* you may want to use */
		char **cp,	/* small comments */
		FPI ptr		/* after the params */
	)

These are ANSI-Prototypes and when converting to K&R-Style using
'awk' a general strategie could be to setup a special context between
lines containing '(' and ')' as first character. (IMHO, it's not
so hard, to avoid such lines in all other parts of the source.)
When in this context, you retard the lines read (easy with an
associative array) extract the parameter-names (more or less
elegant, depending on how familiar you are with 'awk' and how much
of formatting convention you want to put on your source(++).)
and finally output the collected parameters in the old style
before you output the retarded lines, deleting the first '(',
changing embedded kommas and the final ')' to semicolons.

(++) It's *very* easy, if you *allways* use defined types and
separate the kommas with white space, but I think the above
example wouldn't be too hard to do and is less in danger, to
write a declaration wrong by accident. Using defined types
for pointers to functions and the more complex types helps
much - for your tool and for the later reader ... :-)

Such a tool could also automatically produce 'interface files'
for inclusion in any compilation unit, which wants to use foo().
(This last idea of automatically generating interface files
was freely stolen from 'Portable UNIX and C Programming', 
J.E. Lapin, ISBN 0-13-686494-5.)

In article <1066 at root44.co.uk> gwc at root.co.uk (Geoff Clare) writes:
>
>My recommendation is that you do the following:
>
>	#ifndef __STDC__
>	#define const
>	#endif
>
>	int *foo(a)
>	const int a;
>
>Old style declarations are accepted equally well by ANSI compilers
>as 'common C' ones.  The only thing that needs to be dependent on
>__STDC__ being defined is the 'const' keyword.

Yes, I once recommended this solution, but then I stumbled over
this compiler, who told :

	"const can not be redefined, because it will
	become a reserved word in future releases"	:-(
	
I think the guys who wrote that did not know the standard, because
during preprocessing 'const' would *not* be a reserved word.
(Question to all ANSI experts on the net: Am I right?) 
As a workaround for such "clever" compilers, you need to define
an 'intermediate' value, say CONST:

	#ifndef __STDC__
	#define CONST
	#else
	#define CONST const
 	#endif
 
 	int *foo(a)
 	CONST int a;
>
>"But what do I do about prototypes?" I hear you ask.
>
>My answer is the same: just stick to old-style 'extern' declarations.
>The advantage of using prototypes is that you don't need to worry
>about casting function arguments correctly all the time.  But if
>your code must compile with non-ANSI compilers, you're going to have
>to cast all the arguments anyway - so the prototypes are redundant.

IMHO wrong. Some compilers may not do any argument type checking with
'old-style'-declarations. Automatic prototyping in these cases is only
an option, not an obligation (Again question to all ANSI experts:
Am I right? I'm not quite sure.) 

As the author of the original posting allready mentioned, one of
his fears is to get 'out-of-sync' in case of changes. With explicit
casting, he's more in danger to run into that situation, but you
are right, with non-ANSI compilers, this danger allways exists.

-- 
<<< MW -- email: see header -- voice: 49-(0)6151-6 56 83 >>>



More information about the Comp.lang.c mailing list