ints vs. pointers and the type of ioctl(2) 3rd arg

Steve Glaser steveg at hammer.UUCP
Fri Nov 16 16:26:13 AEST 1984


The problem with pointers being longer than integers is a common one.
The X3J11 committe is wrestling with this.

There are even machines (PR1ME for instance) where a pointer won't even
fit into a long (48 bits versus 32 bits I think).

The /usr/group Standards Committe just hit this when we were trying to
specify what the type of the 3rd argument fo ioctl(2) is.  Under K&R C
it's easy - int works just fine since all pointers are coercable to int
without losing anything.

Under X3J11 current draft, a long may not even be enough.

My inclination is to:

1) Specify that the 3rd argument to ioctl(2) be of type (void *).
(void *) is the new X3J11 generic pointer type, suplanting the current
multiple use of (char *).

2) In order to implement #1, we need to get X3J11 to require that an
(int) can be converted to a (void *) and back without loss of
precision.  This is not currently the case as I understand it.

3) If you combine this will the new ANSI C way of specifying argument
types in an external procedure definition, it looks like we might be
able to do all this with no change to existing source programs (at
least on ANSI C compilers).  We would just put something like:

	extern int ioctl(int, int, void *);

in <sys/ioctl.h>.

4) Systems that don't have ANSI C and have pointers larger than
integers would have to resort to changing all user programs that call
ioctl to explicitly cast the 3rd argument.  To help out those systems
we could allow something like:

	typedef void *ioctl_t;

in <sys/ioctl.h> and allow an implementor to replace this an
appropriate type for his machine [(char *) or (int) would be adequate
for most machines, but (void *) would be prefered if it's available].
All calls to ioctl(2) would have to be changed to add a (ioctl_t) cast
in front of the 3rd argument [yeah, it's ugly, but if you don't like
it, fix your compiler].

The only alternatives that have been proposed are:

a) punt, ignore it and maybe it will go away :-)

b) let the type of the 3rd argument be dependant on the 2nd argument in
a similar sense to what happens in printf(3).

c) make the 3rd argument a union of the appriopriate types.

To my mind the problems with these are:

a)  It won't go away, these machines exist now and are in wide use (or
will be) (e.g. iAPX286 in the IBM PC/AT).

b)  This requires the kernel to know about all ioctls.  This has
problems if you want to implement ioctls in a server process (perhaps
over a network).  Yeah, I know you still need to know the size of the
data area and what happens to it but look at 4.2 bsd for a partial
solution to that problem [use the upper bits of the 2nd arg to encode
that - works nice if your int is >16 bits, possible, but uglier, if
your ints are 16 bits].

c)  Requires changing every existing call on ioctl (or you at minimum
get lint errors).  Since you can't cast a pointer or an integer to a
union type you need an intermediate variable that you didn't need
before.

The only problems I can think of with the (void *) approach are:

a)  It really requires an ANSI C compiler.

b)  It assumes that pointers (or at least (void *)) are at least as
large as (int).  [e.g. the exact reverse of the current problem].  I
don't think this is a problem since (void *) is a new concept to C and
thus has no existing implementations to get in the way.  An
implementation could make things so that sizeof(void *) >=
max(sizeof(int), sizeof(char *)) and just ignore any excess bits when
casting to/from (void *).

I'd be interested in any comments on this.

	Steve Glaser
	steveg.tektronix at csnet-relay
	tektronix!steveg



More information about the Comp.lang.c mailing list