Is it conformant to substract two pointer-to-void ?

F

Francois Grieu

Is it OK to substract two pointer-to-void ? Are they guaranteed to act
as pointer-to-char ?
I fail to find that discussed in ISO/IEC 9899:1999.

In other words (hopefully), is the following program guaranteed to
output 1?

#include <stdio.h>
int main(void)
{
char t[2] = {'0','1',};
void *p0,*p1;
p0 = &t[0];
p1 = &t[1];
printf("%d\n",(int)(p1-p0));
return 0;
}

TIA,
Francois Grieu
 
R

Richard Bos

Francois Grieu said:
Is it OK to substract two pointer-to-void ? Are they guaranteed to act
as pointer-to-char ?

No, and no. It's a constraint violation, IIRC.
I fail to find that discussed in ISO/IEC 9899:1999.

That's because it is implicit in the combination of several articles. In
short, you can only subtract pointers to complete object types; void is
an uncompletable type; therefore, void pointers cannot be subtracted.

Richard
 
W

WANG Cong

On Wed, 12 Mar 2008 05:54:56 -0700,Francois Grieu wrote:
Is it OK to substract two pointer-to-void ? Are they guaranteed to act
as pointer-to-char ?
I fail to find that discussed in ISO/IEC 9899:1999.

In other words (hopefully), is the following program guaranteed to
output 1?

#include <stdio.h>
int main(void)
{
char t[2] = {'0','1',};
void *p0,*p1;
p0 = &t[0];
p1 = &t[1];
printf("%d\n",(int)(p1-p0));
return 0;
}

TIA,
Francois Grieu

No, afaik only gcc treats void* as char*.

C99 states:

"For subtraction, one of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of
compatible object types; or
— the left operand is a pointer to an object type and the right operand
has integer type."

And the void* pointer is not a pointer to an object type so should
not take part in this operation directly.
 
K

Keith Thompson

Francois Grieu said:
Is it OK to substract two pointer-to-void ? Are they guaranteed to act
as pointer-to-char ?
I fail to find that discussed in ISO/IEC 9899:1999.

In other words (hopefully), is the following program guaranteed to
output 1?

#include <stdio.h>
int main(void)
{
char t[2] = {'0','1',};
void *p0,*p1;
p0 = &t[0];
p1 = &t[1];
printf("%d\n",(int)(p1-p0));
return 0;
}

Nope.

Why not just declare p0 and p1 as char*? (The answer is that this is
just an example, of course, but there's no good reason not to use
char* in whatever real code this represents.)

gcc allows arithmetic on void* as an extension. As far as I know, gcc
is the only compiler that does this (along with any other compilers
that deliberately imitate it). To make this work, gcc causes
sizeof(void) to yield 1 rather than a compile-time error message.

<OPINION>Ick.</OPINION>

With the "-pedantic" option, gcc warns about this. With a carefully
chosen set of options ("-ansi -pedantic -Wextra -Wall"), gcc is
reasonably close to being a conforming C90 compiler (it merely warns
about some things that are constraint violations, but that's permitted
by the standard).

More generally, most C compilers are not fully conforming by default,
but can be persuaded to be very nearly conforming to one or more C
standards with compile-time options.

Why do you *want* this to work?
 
F

Francois Grieu

Why do you *want* this to work?

My application includes the following:

#define CHK_PTR_TYPE(ptr,basetype) (1?(ptr):((ptr)-(basetype*)(ptr))+
(ptr))

and I am concerned that this wont reliably work when basetype is
void or const void


[My actual application is a set of macros, portable across several
platforms (8051, Win32, others) to store a pointer of parameterized
type, but constrained to belong to some 64KB structure, into a typed 2-
byte structure, so that the conversion is reversible, accidental type
mixes are caught at compile time, and the complexities of memory
domain attributes (xdata and the like) is hidden by the macros.]

Francois Grieu
 
D

Default User

Francois said:
My application includes the following:

#define CHK_PTR_TYPE(ptr,basetype) (1?(ptr):((ptr)-(basetype*)(ptr))+
(ptr))

and I am concerned that this wont reliably work when basetype is
void or const void

But what do you expect the result of it to be? What do you think the
stride of a void pointer should be?





Brian
 
E

Eric Sosman

Francois said:
My application includes the following:

#define CHK_PTR_TYPE(ptr,basetype) (1?(ptr):((ptr)-(basetype*)(ptr))+
(ptr))

and I am concerned that this wont reliably work when basetype is
void or const void

I guess that by "work" you mean "produce a diagnostic if
the type of *ptr is not compatible with basetype?" (If
that's the goal, I don't understand what the addition at the
end is for -- which means that maybe I don't understand what
"work" means. So the rest may be irrelevant ...)

As written, the test should elicit a diagnostic if the
types are incompatible (which is what I think you want), or
if ptr is void* or if basetype is void (which I think you'd
regard as false positives). If you'd be happy with a slightly
different test (compatibility of ptr with basetype* instead
of *ptr with basetype), you might try

#define CHK_PTR_TYPE(ptr,basetype) \
(1 ? (ptr) : (basetype*)(ptr))

.... the idea being that the second and third operands of ?:
must be of compatible pointer types (6.5.15p3), and the
compiler must diagnose a constraint violation.
 
C

CBFalconer

Francois said:
Is it OK to substract two pointer-to-void ? Are they guaranteed
to act as pointer-to-char ?
I fail to find that discussed in ISO/IEC 9899:1999.

In other words (hopefully), is the following program guaranteed
to output 1?

#include <stdio.h>
int main(void) {
char t[2] = {'0','1',};
void *p0,*p1;

p0 = &t[0];
p1 = &t[1];

Fine up to here. The auto pointer to void* has taken effect.
printf("%d\n",(int)(p1-p0));

This should be:
printf("%d\n", (int)((char*)p1 - (char*)p0));
 
F

Francois Grieu

#define CHK_PTR_TYPE(ptr,basetype) (1?(ptr):((ptr)-(basetype*)(ptr))+
(ptr))
I guess that by "work" you mean "produce a diagnostic if
the type of *ptr is not compatible with basetype?"

Yes, that's my goal.
As written, the test should elicit a diagnostic if the
types are incompatible (which is what I think you want), or
if ptr is void* or if basetype is void (which I think you'd
regard as false positives).
Yes.

I don't understand what the addition at the end is for

It is here to make the expression correct. (ptr)-(basetype*)(ptr)
is a ptrdiff_t and we need to add a ptr to make that
compatible with a ptr, on the left side of the :

If you'd be happy with a slightly different test (compatibility
of ptr with basetype* instead of *ptr with basetype), you might
try

#define CHK_PTR_TYPE(ptr,basetype) \
(1 ? (ptr) : (basetype*)(ptr))

... the idea being that the second and third operands of ?:
must be of compatible pointer types (6.5.15p3), and the
compiler must diagnose a constraint violation.

Indeed that SHOULD do the job. <OT> I'll check with the
various compilers that I target, but I'm a bit pessimistic,
I think I remember one of them is hapy with mixing int and
pointers on each side of : </OT>

Francois Grieu
 
F

Francois Grieu

#define CHK_PTR_TYPE(ptr,basetype) (1?(ptr):((ptr)-(basetype*)(ptr))+
(ptr))
But what do you expect the result of it to be? What do you think the
stride of a void pointer should be?

I expect CHK_PTR_TYPE(ptr,basetype) to return the value of ptr after
evaluating it once, or cause a diagnostic at compile time if ptr is
not a pointer to basetype (or a compatible type). This mostly works,
but I whish that it worked if void was assimilated to a type.

Francois Grieu
 
G

Gordon Burditt

Is it OK to substract two pointer-to-void ?

No.
Are they guaranteed to act
as pointer-to-char ?

char *cp;
void *vp;
... initialize cp and vp to point somewhere ...

*cp has type char, and should cause no problems.
*vp has type void, and should cause a compile-time error.

In other words (hopefully), is the following program guaranteed to
output 1?

#include <stdio.h>
int main(void)
{
char t[2] = {'0','1',};
void *p0,*p1;
p0 = &t[0];
p1 = &t[1];
printf("%d\n",(int)(p1-p0));
return 0;
}

On a very old compiler I once used, which claimed C89 conformance
and C99 hadn't been written yet, that program would have caused a
*COMPILE TIME* division by zero fault and core dump of the compiler,
since it treated sizeof(void) as 0. I believe that behavior is
C89-conformant, although the quality-of-implementation, crashing if
the compiler divides by zero, is poor.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top