[comp.lang.c] Type checking in conditional expressions

jholbach@wright.EDU (Jim Holbach) (10/18/87)

	I have been using macros, dummy variables and the C
conditional expression to provide some static type checking that C
compilers don't provide. I have run into a snag that I couldn't
explain or resolve after consulting K&R and was hoping that someone
could help point me in the right direction.
	Here's what I'm doing. C compilers don't check the types
or number of parameters in function calls where the function is 
external to the file being compiled. This has caused me lots of problems
since I'm forgetful and often goof up the actual parameter list for
my function calls. To provide this checking I created some macros
of the form

#define PROCNAME(a,b)	procname(0?dummy_a:(a),0?dummy_b:(b))

where procname is the function that I'm calling and dummy variables 
"dummy_a" and "dummy_b" of the correct types have been declared in the 
include file that contains the macro. Then when I call the function
procname using

	 PROCNAME(actual_a,actual_b)

the compiler has to do type checking on the conditional
expression (without incurring any run-time overhead). This isn't
a perfect solution since if the compiler can bring the dummy variable
and actual variable to a common type through "the usual arithmetic
conversions", it doesn't complain (K&R 7.14).  But at least it takes 
care of the grosser problems, like not using a pointer when 
one was expected, too many/too few arguments, etc. 
	Unfortunately it's also complaining when (I think) it 
shouldn't. For example, I have a function which expects 
a function to be passed to it. So my dummy variable is declared as 
"void (*dummy_func)()". But when I invoke the macro using the name
of the function as an argument, the compiler complains 
"operands of : have incompatible types".
	After consulting K&R about the conditional operator, I tried
some simple test cases like
	main()
		{ void function();
		  void (*name)();
		  name = function;
		  name = (0?name:function);
		}
I figured if name and function were truly incompatible, the first 
assignment should fail to compile, but it didn't. At the same time, 
the compiler complained about the conditional expression in the last line.

	Could someone please explain to me what's going on here?
Thanks.

	Jim Holbach 
	( jholbach@wright.edu )
	Wright State University
	Dayton, Ohio

guy%gorodish@Sun.COM (Guy Harris) (10/19/87)

> 	Here's what I'm doing. C compilers don't check the types
> or number of parameters in function calls where the function is 
> external to the file being compiled. This has caused me lots of problems
> since I'm forgetful and often goof up the actual parameter list for
> my function calls. To provide this checking I created some macros of the
> form...

If you're working on a UNIX system, use "lint".  If you're working on a
non-UNIX system that has "lint" (I think there are, for example, "lint"s for
the PC out there), use "lint".  This does this sort of checking for you,
*without* having to cook up that sort of macro or waste data space, etc. with
dummy variables.  It will also check for a lot of *other* problems, especially
if you use the "-h" flag (or, in the case of later "lint"s, if you *don't* use
the "-h" flag - the default for many of these useful tests was changed from
"don't" to "do").

> 	After consulting K&R about the conditional operator, I tried
> some simple test cases like
> 	main()
> 		{ void function();
> 		  void (*name)();
> 		  name = function;
> 		  name = (0?name:function);
> 		}
> I figured if name and function were truly incompatible, the first 
> assignment should fail to compile, but it didn't. At the same time, 
> the compiler complained about the conditional expression in the last line.
> 
> 	Could someone please explain to me what's going on here?

Yes.  What's happening here is that you're tickling a bug in the compiler.
"name" and "function" are *not* incompatible; the compiler is just confused.
This sounds like a PCC bug, which makes me suspect you're using UNIX, in which
case you should use "lint" instead of that macro trick.  (This bug is fixed in
4.3BSD.)
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guytant,tant,tlif

jholbach@wright.EDU (Jim Holbach) (10/20/87)

in article <186@wright.EDU>, I mentioned a program 

> 	main()
> 		{ void function();
> 		  void (*name)();
> 		  name = function;
> 		  name = (0?name:function);
> 		}

which causes the compiler to complain that the operands of :
in the conditional expression are of incompatible operands.
	It has been pointed out to me that if "int" is 
substituted for "void" in both the declaration of function and
the definition of name, then the program will compile without
any complaints whatsoever.
	Curiouser and curiouser...

throopw@dg-rtp.UUCP (Wayne A. Throop) (10/20/87)

> jholbach@wright.EDU (Jim Holbach)
> To provide [better typechecking] I created some macros of the form
> #define PROCNAME(a,b)	procname(0?dummy_a:(a),0?dummy_b:(b))
> [...] I have a function which expects 
> a function to be passed to it. So my dummy variable is declared as 
> "void (*dummy_func)()". But when I invoke the macro using the name
> of the function as an argument, the compiler complains 
> "operands of : have incompatible types".

This is a symptom of pcc's odd and hacked-in treatment of the void type.
Our non-pcc-based compiler gets this correct, as does our non-pcc-based
typechecker, but lint barfs all over it.  If "void" is replaced by
"int", the problem goes away.

Suggestion: some of the fixes Guy Harris has posted over the last few
years to pcc and lint may make the problem go away.

--
The seeds of crime bear bitter fruit.   --- Dick Tracy
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

chris@mimsy.UUCP (Chris Torek) (10/21/87)

In article <186@wright.EDU> jholbach@wright.EDU (Jim Holbach) writes:
<... I tried some simple test cases like
<	main()
<		{ void function();
<		  void (*name)();
<		  name = function;
<		  name = (0?name:function);
<		}
<I figured if name and function were truly incompatible, the first 
<assignment should fail to compile, but it didn't. At the same time, 
<the compiler complained about the conditional expression in the last line.

You have a buggy compiler.  A number of compilers cannot handle
pointer-to-function-returning-void (4.2BSD in particular).  If
you `#define void int' the problem sort of goes away.

On the other hand, all the type checking you are getting via preprocessor
macros you can also get by using lint, and lint will do a better job.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guy%gorodish@Sun.COM (Guy Harris) (10/23/87)

> Suggestion: some of the fixes Guy Harris has posted over the last few
> years to pcc and lint may make the problem go away.

Thanks for the vote of confidence, but it's not warranted in this case.  I
never, to my knowledge, posted a fix for this.  It is fixed in the 4.3BSD
"pcc"; it also appears to be fixed in the 3B2 S5R3 PCC2-based compiler, but
*not* in the S5R3 PCC1-based "lint".
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com