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

Discussion in 'C Programming' started by Francois Grieu, Mar 12, 2008.

  1. 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
    Francois Grieu, Mar 12, 2008
    #1
    1. Advertising

  2. Francois Grieu

    Richard Bos Guest

    Francois Grieu <> wrote:

    > 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
    Richard Bos, Mar 12, 2008
    #2
    1. Advertising

  3. Francois Grieu

    WANG Cong Guest

    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.

    --
    Hi, I'm a .signature virus, please copy/paste me to help me spread
    all over the world.
    WANG Cong, Mar 12, 2008
    #3
  4. Francois Grieu <> writes:
    > 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?

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Mar 12, 2008
    #4
  5. > 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
    Francois Grieu, Mar 12, 2008
    #5
  6. Francois Grieu

    Default User Guest

    Francois Grieu wrote:

    > > 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


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





    Brian
    Default User, Mar 12, 2008
    #6
  7. Francois Grieu

    Eric Sosman Guest

    Francois Grieu wrote:
    >> 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


    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.

    --
    Eric Sosman, Mar 12, 2008
    #7
  8. Francois Grieu

    CBFalconer Guest

    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];


    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));

    > return 0;
    > }


    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Mar 12, 2008
    #8
  9. On 12 mar, 22:36, Eric Sosman <> wrote:
    > Francois Grieu wrote:
    >>> 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

    >
    > 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
    Francois Grieu, Mar 13, 2008
    #9
  10. On 12 mar, 22:34, "Default User" <> wrote:
    > Francois Grieu wrote:
    >>> 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

    >
    > 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
    Francois Grieu, Mar 13, 2008
    #10
  11. >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.
    Gordon Burditt, Mar 14, 2008
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ollej Reemt
    Replies:
    7
    Views:
    498
    Jack Klein
    Apr 22, 2005
  2. Stig Brautaset

    `void **' revisited: void *pop(void **root)

    Stig Brautaset, Oct 25, 2003, in forum: C Programming
    Replies:
    15
    Views:
    773
    The Real OS/2 Guy
    Oct 28, 2003
  3. Replies:
    5
    Views:
    814
    S.Tobias
    Jul 22, 2005
  4. Replies:
    1
    Views:
    389
    Victor Bazarov
    May 23, 2007
  5. Alexandre Jaquet

    substract two time var

    Alexandre Jaquet, Mar 1, 2005, in forum: Perl Misc
    Replies:
    2
    Views:
    76
    Gunnar Hjalmarsson
    Mar 1, 2005
Loading...

Share This Page