[comp.lang.c] Variadic argument functions

andrew@teletron.UUCP (Andrew Scott) (04/14/88)

In article <7667@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <5980@utcsri.UUCP> flaps@utcsri.UUCP (Alan J Rosenthal) writes:
> >In C it is permissible to call any function (including
> >user-defined ones) with the wrong number of arguments, so long as any
> >arguments not actually passed are not accessed by the function being
> >called.
> 
> Not true in general.  If you read Dennis's anti-noalias diatribe,
> near the end you may recall that he identified two botches in original
> C, one of which was that printf()-like functions existed without
> adequate language support.  The reason for the ,... approach of ANSI
> C is to provide adequate language support for variadic arguments.

I am working on a bit of code in which I call a vectored function.  The code
to invoke the vector goes something like this:

	void (*vector)();
	int arg;

	(*vector)(arg);

The integer argument is available to the function if necessary; sometimes the
vectored function doesn't need the argument.

Now, a question related to the above comments.  Is the following code "bad"?
That is, should I re-work it so that all possible functions assigned to the
vector have exactly one integer argument, as to be consistent with the vector
call?

	void funcA(arg)
	int arg;
	{
		/* do something */
	}

	void funcB()
	{
		/* do something else */
	}

	...

	vector = funcA;		/* this is fine */
	vector = funcB;		/* is this? */

I'm hoping that I can leave it as it is, because funcA() and funcB() are library
functions, and I wouldn't want to have kludgey function argument interfaces with
unused arguments, etc.

Also, I have a totally unrelated question.  In making a library of functions, I
have run into a couple of problems with the argument interface to some func-
tions.  Specifically, suppose one (integer) argument is range limited to values
in the range 0..1000.  Should the argument be of type short, to emphasize the
range of the argument?  Or, should I use ints everywhere and simply document
the range of acceptable argument values.  How about function return values?
If the value is also range limited, should I use a smaller type or just docu-
ment the range of return values so that a user of the function can cast it into
a smaller type for storage purposes if desired.  I was looking to UNIX libraries
for inspiration; the aproach there seems to be "use int for everything except
use long for large values".

Thanks.
-- 
Andrew Scott
andrew@teletron.uucp	or	..alberta!teletron!andrew

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/16/88)

In article <253@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>	(*vector)(arg);
>	void funcA(arg)
>	void funcB()

For maximal portability, your functions all need to have identical
interfaces, either precisely the same number and types of arguments
and return value, or all variadic arguments (in which case there must
still be at least one fixed "anchor" argument of the same type).

On a large number of architectures, though, you can get away with
your current approach.

>in the range 0..1000.  Should the argument be of type short, to emphasize the
>range of the argument?  Or, should I use ints everywhere and simply document
>the range of acceptable argument values.  How about function return values?

The main reason most existing functions use int is that that was the
type to which all smaller integral types were widened at the function
interface.  This widening is not required for ANSI C when prototypes
are used.

The best style would be to use the appropriate type AND document the
interface.  The safest thing to do is to use int anyway, because some
compilers may incorrectly handle other function definitions (they
aren't supposed to mishandle these, but it's been known to happen).

flaps@dgp.toronto.edu (Alan J Rosenthal) (04/17/88)

In article <253@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>	void (*vector)();
>	int arg;
>
>	(*vector)(arg);
>
...
[ possible values of `vector' are the following two functions: ]
>
>	void funcA(arg)
>	int arg;
>	{
>		/* do something */
>	}
>
>	void funcB()
>	{
>		/* do something else */
>	}
>
...
>should I re-work it so that all possible functions assigned to the
>vector have exactly one integer argument, as to be consistent with the
>vector call?

I argue that as is it is fine K&R C (if you like, "pre-ansi C").
Others here have recently disagreed with me.

It definitely is invalid ANSI C and should be re-worked as you say.
You may also want to change the declaration of vector to something more
like "void (*vector)(int);".

>Also, I have a totally unrelated question...
>Suppose one (integer) argument is limited to values in the range
>0..1000.  Should the argument be of type short, to emphasize the range
>of the argument?  Or should I use ints everywhere and simply document
>the range of acceptable argument values?  How about function return
>values?

The argument is not of type short.  If you examine the default
arithmetic promotions, you will see that shorts in an expression become
ints.  Therefore it is impossible to actually pass a short, since the
mention of a short is an int-valued, not short-valued, expression.[1]
In other words, "SHOULD the argument be of type short" is not the question.

[ Also, you would still have to document the range limitation, as
``short'' allows -32768 to 32767, not just 0 to 1000. ]

Unfortunately, compilers do not give an error message for a declaration
such as

	int f(x)
	    short x;
	{
	    ...
	}

In fact, K&R, and all current practice, makes it quite clear that the
short declaration is simply rewritten to be an int declaration.
(The same behaviour happens for array formal declarations, which are
rewritten as pointer declarations due to the conversion of array names
to pointers in expressions.)

I think that this rewriting is bizarre, but some people take advantage
of it for "comment" purposes.  You may choose to use "short" for this
purpose in your functions, but I would recommend against it as this
bizarre rewriting can cause some strange facts.  For example, within
the function `f' as defined above, the call ``scanf("%hd",&x)'' would
be invalid as x is not a short, it is an int.

Now as for function return values, the situation is not quite the
same.  For these I would argue for using int rather than char or short
for the same reason I would argue against using char or short for
single variables (i.e. when they're not part of a larger object like an
array).  This is simply that since they keep getting converted to ints
for calculations, it really isn't helpful to merely store them as
smaller objects.  In the case of function return values which are
probably just in a register somewhere anyway, the advantage then
becomes zero and the penalty remains non-zero.

ajr

--
[1] In ANSI-compatible compilers it will be possible to pass shorts and
chars, by using the Pascal-style declarations.  This is used in some of
the library functions.  Obviously, some people consider this advantageous.
I personally can only see the advantage on 8-bit machines.
--
Make:  Don't know how to keep up with all the new features.  Stop.