[net.lang.c] Portability enhancing C extension

dapermezel@watmath.UUCP (Damon Permezel) (10/01/83)

The addition of the ability to type the expected args of an external function
is definitely needed in C. All you VAX-C programmers have lead a sheltered
life and can't be expected to realise the need. Consider the much abused

	f(0);

where 'f' is

f(p)
char *p; { ... }

This works fine on the VAX, but will not work on a HW level-6, which has
different sizes for each of 'int', 'int *' and 'char *'. It will also fail
on the 68000, where sizeof(int) == 2 and sizeof(int *) == sizeof(char *) == 4.

When we ported our compiler source from the HW DPS/8 (sizeof(most_stuff) == 4)
to the level-6, we had one hell of a time (we had no lint then). If my
language extension that allows

extern f(char *);

had been working then, most of the problems would have gone away with the
inclusion of a "ext_def.h" file that defined the arg types, allowing the
compiler to add the cast where necessary.

I was very reluctant to add any language extensions to my parser, but
this one i definitely consider worthwhile.

=damon

notes@ucbcad.UUCP (10/02/83)

#R:watmath:-587000:ucbesvax:4800025:000:2310
ucbesvax!turner    Oct  1 18:00:00 1983

I, like, totally grok what you mean.  The problem of C not knowing (or
much caring) about types of arguments of external functions is not
completely alleviated by lint, since, to be fully useful, we would
also want to have pointers to functions, with argument-types checked.
(lint can't do this, in general, so it doesn't do it at all.)

I have an interesting little hack, which works for my situation.  I am
charged with defining and maintaining (not mention implementing), a
special-purpose database.  To provide a security blanket, I define all
entry-points in a global #include file as macros, where the *real* names
of access routines are all icked-out with underscores.  This takes care
of *numbers* of arguments (since cpp complains of argument mismatches).

But what about the *types* of arguments?  My people here don't use lint
(and their code shows it!), so giving them a lint library is no help.
After a bit of C-puzzling, I came up with the following ultra-cutesy-
but-probably-portable macro:

    #define _declare_(Expr,Type) ( sizeof((Expr) == (Type) 0), (Expr) )

	/* Example: */
    extern SomeStruct *_Icky_Real_Name_( );

    #define FakeName(arg1,arg2) \
		_Icky_Real_Name_( _declare_(arg1,char *), \
				  _declare_(arg2,SomeStruct) )

Now, calls through FakeName must have exactly two arguments, one (char *),
the next of type SomeStruct, if they are to compile without errors.

Exegesis of "_declare_":

	"( sizeof(...), (Expr) )" = (Expr), loosely speaking; sizeof(...)
	is a constant, and the code generator throws it out, since a
	constant can't have side-effects.  The comma operator was a
	good idea.

	Also, sizeof(...) suppresses any code generation for (...).
	Thus we circumvent a problem with macros: that multiple mentions
	of a formal parameter involve multiple evaluations of the actual
	parameter--bad craziness, but we get around it here.

	Finally, "(Expr) == (Type) 0" will generate an error message,
	if the type of Expr is incomparable with something of type Type.

But, given a choice, I would rather exercise my remaining inventive powers
in ways other than hacking around holes in C.  Especially considering that
my inventive powers are out to lunch a lot, these days.

    No Strong-Typing vs. Weak-Typing Jihads, Please,
	Michael Turner (ucbvax!ucbesvax.turner)

thomas@utah-gr.UUCP (Spencer W. Thomas) (10/03/83)

Note: lint flags f(0) as a type mismatch, if f() has a pointer
argument.  This is true even if you are not asking for portability
checks.   (This is under 4.1Bsd.)

=S