[comp.std.c] Void pointers and pointer arithmetic

arne@yc.estec.nl (Arne Lundberg) (01/02/90)

I am trying to write some code that tries to access members in a structure
by knowing the start address and the offset to a particular member element.
The following program shows a small example (the real program does not 
hardcode the offsets etc.) Is this program legal in ANSI C, will it
produce the desired result? 

The (Non-ANSI) compilers I have tested either gives the value for `a'
three times or complains about ``unknown size for pointer to void''.
It works perfectly well if I change the type of p to be ``char *''.

---------------------------------------
struct x {
    int a, b, c;
} x = {
    1, 2, 3
};

main()
{
    void *p = &x;
    printf("a %d\n", *(int *)(p + 0));
    printf("b %d\n", *(int *)(p + 4));
    printf("c %d\n", *(int *)(p + 8));
}
---------------------------------------


BTW,
is it possible to write an ANSI compatible ``offsetof'' macro
for traditional C compilers? I am now using the XtOffset macro
from the X11/Toolkit but would like to have something that doesn't
require an additional name for the ``pointer to the structure'' type.

Arne Lundberg

European Space Technology Centre, Noordwijk, the Netherlands
arne@yc.estec.nl or ALUNDBER@ESTEC.BITNET
Phone: +31 1719 84865, Fax: +31 1719 12142, Telex: 39098

henry@utzoo.uucp (Henry Spencer) (01/03/90)

In article <1055@esatst.yc.estec.nl> arne@yc.estec.nl (Arne Lundberg) writes:
>...Is this program legal in ANSI C, will it
>produce the desired result? 

No.  Pointer arithmetic is not defined for pointer-to-void.  It can't be,
since it's not possible to do pointer arithmetic without knowing the size
of the type pointed to.

>BTW,
>is it possible to write an ANSI compatible ``offsetof'' macro
>for traditional C compilers? ...

Sort of.  We do this in C News.  Here's what we say about it in our
porting-problems document (C News enthusiasts:  this will be in the
next patch):

	Unfortunately, it is really hard to write a portable version of this.
	The implementation we currently use is:
	.DS
	#define offsetof(type, mem) ((char *)&((type *)NULL)->mem - (char *)NULL)
	.DE
	The table in \fIrelay/hdrdefs.c\fR
	puts invocations of \fIoffsetof\fR in initializers.
	This turns out to be a severe stress test for C compilers.
	A compilation error in \fIhdrdefs.c\fR is almost certain
	to be problems with this macro.
	Some compilers,
	notably the one in Microport System V Release 2.3,
	reject it.
	We have heard a report that System V Release 2 on the VAX silently
	miscompiles it!
	If you have trouble with \fIoffsetof\fR, you might try
	this version instead:
	.DS
	#define offsetof(type, mem) ((int)&((type *)NULL)->mem)
	.DE
-- 
1972: Saturn V #15 flight-ready|     Henry Spencer at U of Toronto Zoology
1990: birds nesting in engines | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

bill@twwells.com (T. William Wells) (01/03/90)

In article <1055@esatst.yc.estec.nl> arne@yc.estec.nl (Arne Lundberg) writes:
:
: I am trying to write some code that tries to access members in a structure
: by knowing the start address and the offset to a particular member element.
: The following program shows a small example (the real program does not
: hardcode the offsets etc.) Is this program legal in ANSI C, will it
: produce the desired result?
:
: The (Non-ANSI) compilers I have tested either gives the value for `a'
: three times or complains about ``unknown size for pointer to void''.
: It works perfectly well if I change the type of p to be ``char *''.
:
: ---------------------------------------
: struct x {
:     int a, b, c;
: } x = {
:     1, 2, 3
: };
:
: main()
: {
:     void *p = &x;
:     printf("a %d\n", *(int *)(p + 0));
:     printf("b %d\n", *(int *)(p + 4));
:     printf("c %d\n", *(int *)(p + 8));
: }
: ---------------------------------------

This is not legal ANSI C. About the only things you can do with
void * are cast them, assign them, and pass them as function
arguments.

: is it possible to write an ANSI compatible ``offsetof'' macro
: for traditional C compilers?

There is no way to write an offsetof macro that will work on all
compilers. There are a number of ways to write it that will work
on most non-ANSI compilers.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

bts@sas.UUCP (Brian T. Schellenberger) (01/07/90)

In article <1990Jan3.073624.14061@twwells.com> bill@twwells.com (T. William Wells) writes:
|In article <1055@esatst.yc.estec.nl> arne@yc.estec.nl (Arne Lundberg) writes:
|:
|: I am trying to write some code that tries to access members in a structure
|: by knowing the start address and the offset to a particular member element.
|: The following program shows a small example (the real program does not
|: hardcode the offsets etc.) Is this program legal in ANSI C, will it
|: produce the desired result?
|:
|: The (Non-ANSI) compilers I have tested either gives the value for `a'
|: three times or complains about ``unknown size for pointer to void''.
|: It works perfectly well if I change the type of p to be ``char *''.
|:
|: ---------------------------------------
|: struct x {
|:     int a, b, c;
|: } x = {
|:     1, 2, 3
|: };
|:
|: main()
|: {
|:     void *p = &x;
|:     printf("a %d\n", *(int *)(p + 0));
|:     printf("b %d\n", *(int *)(p + 4));
|:     printf("c %d\n", *(int *)(p + 8));
|: }
|: ---------------------------------------

. . . so just use "char *"; this works under ANSI, too.

1. offsetof is the size in bytes.  (4.1.5)
2. sizeof yields the sie in bytes;
   When applied to char . . . the result is 1.  (3.3.3.4)
3. A pointer to void shall htave the representation and
   alignment requirements as a pointer to character type (3.1.2.5,
   the paragraph just before examples).


Ergo, this must work under ANSI with char *.
-- 
-- Brian, the Man from Babble-on.		...!mcnc!rti!sas!bts
-- (Brian Schellenberger)
"No one will ever write a song called 'Nitro Burning Funny Cars'"
                 -- THE DEAD MILKMEN, "Nitro Burning Funny Cars"