cdecl keyword

Alan J Rosenthal flaps at dgp.toronto.edu
Sat Apr 16 05:30:33 AEST 1988


Recently, I (flaps at dgp.toronto.edu (Alan J Rosenthal)) wrote that
before ANSI C it was generally accepted that variadic functions were
allowed in C so long as you didn't use any parameters not actually
passed.  For instance, I claimed that this was valid:

	main()
	{
	    f(1);
	    ...
	}

	int f(a,b)
	    int a,b;
	{
	    if(a == 1)
		return(5);
	    ...
	}

Doug Gwyn, Karl Heuer, and Henry Spencer all took objection to this.
They said that dmr's recent posting said that in K&R C variadic
functions are forbidden (an aside from the point of that item in that
posting, which was that this is an inconsistency in K&R C, since printf
exists).  In particular, Henry said that I was confusing what you can
get away with in certain common implementations with what is guaranteed
by C.

I disagree.  (I would like to point out that I have done this in
non-unix C implementations as well.  I no longer do, as putting a dummy
extra argument is clearer and has no disadvantages.)  I am interested
in hearing about implementations (pre-ansi only, please!) in which the
above code segment causes problems.  I would be surprised if there is
none, but I would like to point out that for most rules in C there
exists AN implementation that violates it.

I would also like to draw your attention to the first sentence in the
fourth paragraph in section 4.3 on page 71 of K&R, which states that
"It is generally safe to deal with a variable number of arguments if
the called function doesn't use an argument which was not actually
supplied, and if the types are consistent."  Note that the main
objection to the portability of variadic functions is that "there is no
portable way for the called function to determine how many arguments
were actually passed to it" (previous paragraph), not that the
arguments may be pushed in reverse order a la Pascal.

Also, just to throw some more fuel into the fire, I would like to point
out that the idea of rules which defined C and guaranteed portable
behaviour was not present in K&R in the sense in which this idea is
conceived today.  For example, on page 163 we find the function:

	error(s1, s2)  /* print error message and die */
	char *s1, *s2;
	{
	    printf(s1, s2);
	    printf("\n");
	    exit(1);
	}

Looking above it to see how it is called, we see the line "#define NULL 0"
and a second argument of "NULL", _not_ "(char *)NULL".

This can be explained by assuming that sizeof(char *) == sizeof(int)
and that, even if (int)0 is an invalid char *, it will never be
examined by printf due to the format string so it's ok.  It can also be
explained by assuming that even if sizeof(char *) != sizeof(int) things
will work out ok due to my above assumption, plus a little extra
assumption that grabbing garbage off the stack and passing it around is
fine so long as you don't ever look at it.  (Admittedly this last
justification suggests calling it without a second argument altogether,
unless you're worried about stack underflow.)

ajr

--
extern volatile const noalias wellbehaved int f();




More information about the Comp.lang.c mailing list