question realted to void *

Discussion in 'C Programming' started by junky_fellow@yahoo.co.in, Sep 16, 2008.

  1. Guest

    Guys,

    Consider a function
    func(void **var)
    {

    /* In function I need to typecast the variable var as (int **)
    I mean to say, I need to access var as (int **)

    }

    My question is what is the better option, should I use
    func(void **var) Or
    func(void *var).

    I think func(void *) should be fine, as we can store any type of
    "pointer variable" in "void pointer variable".
    void pointer variable should be big enough to hold any type of pointer
    variable.

    Is that correct? Or I am missing something?

    And if that is correct, should we ever use void ** ?

    thanks for any help/response.
     
    , Sep 16, 2008
    #1
    1. Advertising

  2. Guest

    On Sep 16, 4:54 pm, ""
    <> wrote:
    > Guys,
    >
    >    Consider a function
    > func(void **var)
    > {
    >
    > /* In function I need to typecast the variable var as (int **)
    >    I mean to say,  I need to access var as (int **)
    >
    > }
    >
    > My question is what is the better option, should I use
    > func(void **var)  Or
    > func(void *var).
    >
    > I think func(void *) should be fine, as we can store any type of
    > "pointer variable" in "void pointer variable".
    > void pointer variable should be big enough to hold any type of pointer
    > variable.
    >
    > Is that correct? Or I am missing something?
    >
    > And if that is correct, should we ever use void ** ?
    >
    > thanks for any help/response.


    You can cast anything to anything you want, but the less confusing you
    can make it, the better. Ideally, func() would take an "int** var" if
    that is what it really is. However, sometimes, as appears to be true
    in this case, it is necessary to use void. If you need to use void,
    then I would still prefer "void**" if what you are passing really is a
    pointer-to-pointer.

    To me what matters more than how you cast "var" inside the function,
    is what the function signature tells the client caller. If I'm going
    to call a function with a signature "func(void*)" then I expect to
    pass a pointer, not a pointer-to-pointer. For example:

    void f1(void*);
    void f2(void**);

    int x = 0;
    int* px = &x;

    f1(px); /* pointer */
    f2(&px); /* pointer to pointer */

    Adam
     
    , Sep 16, 2008
    #2
    1. Advertising

  3. "" <> writes:
    [...]
    > And if that is correct, should we ever use void ** ?


    void* can be used as a generic pointer type. What that means is that
    a value of any pointer type (other than a pointer-to-function type)
    can be converted to void* and back again without loss of information.

    You might think that void** is therefore a generic pointer-to-pointer
    type, but it isn't; in fact, there is no generic pointer-to-pointer
    type.

    You can convert an int*, or an int**, or an int***, or ... to void*
    without loss of information -- except that you lose the type
    information, which you have to carefully keep track of yourself.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 16, 2008
    #3
  4. CBFalconer Guest

    Malcolm McLean wrote:
    > <> wrote in message
    >
    >> And if that is correct, should we ever use void ** ?

    >
    > A void ** is for a list of pointers to arbitrary memory buffers.
    > A void * is for a pointer to an arbitary memory buffer.


    No, a void** is for a pointer to a void*. When an array of void*
    is passed anywhere, the reference is made with a void**. Just the
    same as any other array reference.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.
     
    CBFalconer, Sep 16, 2008
    #4
  5. wrote:
    > <> wrote:
    > >    Consider a function
    > > func(void **var)
    > > {
    > > /* In function I need to typecast the variable var as
    > > (int **)
    > >    I mean to say,  I need to access var as (int **)
    > > }
    > >
    > > My question is what is the better option, should I use
    > > func(void **var)  Or
    > > func(void *var).
    > >
    > > I think func(void *) should be fine, as we can store
    > > any type of "pointer variable" in "void pointer
    > > variable".


    You can store any pointer to an object or incomplete type.

    > > void pointer variable should be big enough to hold any
    > > type of pointer variable.


    There is no requirement for void * to be big enough to
    hold function pointers.

    > > Is that correct? Or I am missing something?
    > >
    > > And if that is correct, should we ever use void ** ?

    >
    > You can cast anything to anything you want,


    You can try. But you can also fail in the attempt.

    > but the less confusing you can make it, the better.
    > Ideally, func() would take an "int** var" if that is
    > what it really is. However, sometimes, as appears to
    > be true in this case, it is necessary to use void. If
    > you need to use void, then I would still prefer
    > "void**" if what you are passing really is a
    > pointer-to-pointer.


    Just realise that the guarantees that go with void * are
    not necessarily available to void **.

    > To me what matters more than how you cast "var" inside
    > the function, is what the function signature tells the
    > client caller. If I'm going to call a function with a
    > signature "func(void*)" then I expect to pass a pointer,
    > not a pointer-to-pointer. For example:
    >
    >     void f1(void*);
    >     void f2(void**);
    >
    >     int x = 0;
    >     int* px = &x;
    >
    >     f1(px);    /* pointer */
    >     f2(&px);   /* pointer to pointer */


    This violates a constraint. There is no implicit
    conversion to or from void ** as there is for void *.

    But even if I cast &px in the call to f2, there is no
    guarantee that the conversion of &px to void ** succeeds.

    Whilst unlikely in practice, the standard allows void *
    to have stricter alignment than int *. In that case, the
    conversion of int ** to void ** can fail.

    --
    Peter
     
    Peter Nilsson, Sep 16, 2008
    #5
  6. Guest

    >
    > With the possible exception of function pointers, yes (and broadly
    > speaking, this is why C doesn't guarantee that you can store function
    > pointers in a void *).
    >
    > > Is that correct? Or I am missing something?

    >
    > You're missing the obvious: void func(int **var)
    >


    Actually, I want to typecast "var" with some structure type. Just to
    keep it simple I used "int".
    However, the conclusion the I make is as follows. Please correct me if
    I am wrong.

    1) There is nothing wrong in using "void *" (in case var is not a
    function pointer).
    2) Using "void **" is a better option as it is more readable and we
    don't lose the pointer-type information.

    thanks a lot guys..
     
    , Sep 17, 2008
    #6
  7. James Kuyper Guest

    wrote:
    > Guys,
    >
    > Consider a function
    > func(void **var)
    > {
    >
    > /* In function I need to typecast the variable var as (int **)
    > I mean to say, I need to access var as (int **)
    >
    > }
    >
    > My question is what is the better option, should I use
    > func(void **var) Or
    > func(void *var).
    >
    > I think func(void *) should be fine, as we can store any type of
    > "pointer variable" in "void pointer variable".
    > void pointer variable should be big enough to hold any type of pointer
    > variable.
    >
    > Is that correct? Or I am missing something?


    Any pointer to an object type can be converted to void* and back.
    However, that does not mean that void* is compatible with all of those
    other pointer type; it's only guaranteed to be compatible with pointers
    to character types.

    When you dereference a pointer, the pointed-at object has to have an
    effective type that is compatible with the type pointed at by the
    pointer, it can't have a type that is merely convertible to it. That's a
    simplification of the real rules, but it's good enough for the purposes
    of this explanation.

    A void** is a pointer to a pointer to void. When you dereference it, it
    has to be pointing at an actual pointer to void; it can't be pointing at
    an pointer to int. int** is a pointer to a pointer to int. If you
    convert an int** to a void**, dereferencing it might not work. You can't
    convert it back to an int** and be sure that it compares equal to the
    original pointer - that guarantee applies to void*, not void**. You
    can't even guarantee that a void* has the same alignment requirements as
    an int*; as a result, even the conversion of an int** to a void** could
    have undefined behavior.

    func(void*) is the right approach - just make sure you do it properly:

    void func(void*p)
    {
    int **q = (int**)p;
    // Use q for the real work.
    }

    I presume that there's some important reason why you can't simply
    declare func(int **)? That would be the best approach, unless there's
    something that prevents you from using it.


    > And if that is correct, should we ever use void ** ?


    Yes, certainly:

    int i;
    void *p = &i;
    void *arr[] = {&i, &p};

    If you want to call func(&p) or func(arr), then you should declare it as
    func(void**).
     
    James Kuyper, Sep 17, 2008
    #7
  8. "" <> writes:

    >>
    >> With the possible exception of function pointers, yes (and broadly
    >> speaking, this is why C doesn't guarantee that you can store function
    >> pointers in a void *).
    >>
    >> > Is that correct? Or I am missing something?

    >>
    >> You're missing the obvious: void func(int **var)

    >
    > Actually, I want to typecast "var" with some structure type. Just to
    > keep it simple I used "int".
    > However, the conclusion the I make is as follows. Please correct me if
    > I am wrong.
    >
    > 1) There is nothing wrong in using "void *" (in case var is not a
    > function pointer).
    > 2) Using "void **" is a better option as it is more readable and we
    > don't lose the pointer-type information.


    Richard Heathfield has given you a detailed answer, but just in case
    it helps clarify things, this question reads, to me, like this:

    "I have object of type X. Is it better to use Y * or Y **?"
    I.e. which of two wrong types is better? I think you are still not
    asking the real question because you must be casting the pointer to
    another type for some reason but we don't yet know why.

    --
    Ben.
     
    Ben Bacarisse, Sep 17, 2008
    #8
  9. James Kuyper <> writes:
    [...]
    > Any pointer to an object type can be converted to void* and
    > back. However, that does not mean that void* is compatible with all of
    > those other pointer type; it's only guaranteed to be compatible with
    > pointers to character types.

    [...]

    I understand what you mean, but "compatible" isn't the word for it.
    The standard has a very specific definition for "compatible types"; by
    that definition, void* and char* are not compatible.

    C99 6.7.5.1p2:

    For two pointer types to be compatible, both shall be identically
    qualified and both shall be pointers to compatible types.

    Since void and char are not compatible, void* and char* are not
    compatible.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 17, 2008
    #9
  10. wrote:
    > Guys,
    >
    > Consider a function
    > func(void **var)
    > {
    >
    > /* In function I need to typecast the variable var as (int **)
    > I mean to say, I need to access var as (int **)
    >
    > }
    >
    > My question is what is the better option, should I use
    > func(void **var) Or
    > func(void *var).


    func(void *var)

    > I think func(void *) should be fine, as we can store any type of
    > "pointer variable" in "void pointer variable".


    Yes. Moreover, that's the only option that's really "fine", as opposed
    to 'void**' one.

    > void pointer variable should be big enough to hold any type of pointer
    > variable.


    Yes, as long as you are talking about pointer-to-data types.

    > And if that is correct, should we ever use void ** ?


    Hm... Yes. As well as 'void***', 'void****' and so on. Why not? The
    general concept of "rising the level of indirection" is not really
    related to the concept of "generic pointer type".

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Sep 17, 2008
    #10
  11. James Kuyper Guest

    Keith Thompson wrote:
    > James Kuyper <> writes:
    > [...]
    >> Any pointer to an object type can be converted to void* and
    >> back. However, that does not mean that void* is compatible with all of
    >> those other pointer type; it's only guaranteed to be compatible with
    >> pointers to character types.

    > [...]
    >
    > I understand what you mean, but "compatible" isn't the word for it.
    > The standard has a very specific definition for "compatible types"; by
    > that definition, void* and char* are not compatible.
    >
    > C99 6.7.5.1p2:
    >
    > For two pointer types to be compatible, both shall be identically
    > qualified and both shall be pointers to compatible types.
    >
    > Since void and char are not compatible, void* and char* are not
    > compatible.


    You're right: the standard requires them to have the same alignment
    requirements and same representation, but they are not compatible
    according to C's definition of the term. This is another of those cases
    where the standard falls short of actually saying something that I think
    it was actually intended to say. As a practical matter, they work just
    as if they were compatible, on most implementations.

    When I wrote: "That's a simplification of the real rules, but it's good
    enough for the purposes of this explanation.", I should have made it
    clear that this statement applied to both of the preceeding paragraphs,
    not just the immediately preceding one.
     
    James Kuyper, Sep 17, 2008
    #11
  12. On Wed, 17 Sep 2008 17:37:51 +0000, James Kuyper wrote:
    > Keith Thompson wrote:
    >> James Kuyper <> writes: [...]
    >>> Any pointer to an object type can be converted to void* and back.
    >>> However, that does not mean that void* is compatible with all of those
    >>> other pointer type; it's only guaranteed to be compatible with
    >>> pointers to character types.

    >> [...]
    >>
    >> I understand what you mean, but "compatible" isn't the word for it. The
    >> standard has a very specific definition for "compatible types"; by that
    >> definition, void* and char* are not compatible.
    >>
    >> C99 6.7.5.1p2:
    >>
    >> For two pointer types to be compatible, both shall be identically
    >> qualified and both shall be pointers to compatible types.
    >>
    >> Since void and char are not compatible, void* and char* are not
    >> compatible.

    >
    > You're right: the standard requires them to have the same alignment
    > requirements and same representation, but they are not compatible
    > according to C's definition of the term. This is another of those cases
    > where the standard falls short of actually saying something that I think
    > it was actually intended to say. As a practical matter, they work just
    > as if they were compatible, on most implementations.


    My compiler reports an error when I try

    void f(char *p);
    void f(void *p) {}

    My compiler doesn't report an error when I try

    void f(void *p);
    void f(void *p) {}

    or when I try

    void f(int (*p)[]);
    void f(int (*p)[30]) {}

    I have trouble believing the intent was to allow the first, or that you
    believe that was intended. If char * and void * were compatible, it would
    be allowed, because compatible means something different from how you are
    using it.
     
    Harald van Dijk, Sep 17, 2008
    #12
  13. James Kuyper <> writes:
    > Keith Thompson wrote:
    >> James Kuyper <> writes:
    >> [...]
    >>> Any pointer to an object type can be converted to void* and
    >>> back. However, that does not mean that void* is compatible with all of
    >>> those other pointer type; it's only guaranteed to be compatible with
    >>> pointers to character types.

    >> [...]
    >> I understand what you mean, but "compatible" isn't the word for it.
    >> The standard has a very specific definition for "compatible types"; by
    >> that definition, void* and char* are not compatible.
    >> C99 6.7.5.1p2:
    >> For two pointer types to be compatible, both shall be identically
    >> qualified and both shall be pointers to compatible types.
    >> Since void and char are not compatible, void* and char* are not
    >> compatible.

    >
    > You're right: the standard requires them to have the same alignment
    > requirements and same representation, but they are not compatible
    > according to C's definition of the term. This is another of those
    > cases where the standard falls short of actually saying something that
    > I think it was actually intended to say. As a practical matter, they
    > work just as if they were compatible, on most implementations.
    >
    > When I wrote: "That's a simplification of the real rules, but it's
    > good enough for the purposes of this explanation.", I should have made
    > it clear that this statement applied to both of the preceeding
    > paragraphs, not just the immediately preceding one.


    Another way in which they aren't compatible is this:

    int main(void)
    {
    char *pc;
    void *pv;

    char **ppc = &pc;
    void **ppv = &pv;

    ppc = ppv; /* constraint violation */
    ppv = ppc; /* constraint violation */

    return 0;
    }

    char* and void* can be assigned to each other, but only because
    there's an implicit conversion (which, given the requirement for them
    to have the same representation, will merely reinterpret the bits).

    Since char* and void* are incompatible, pointers to those types are
    incompatible, and cannot be assigned to each other because there is no
    implicit conversion.

    The standard implies that various types of type-punning between char*
    and void* (and unsigned char*, and signed char*) are safe, but that
    doesn't affect the many contexts that require compatible types.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 17, 2008
    #13
  14. Guest

    Harald van D©¦k wrote:
    > On Wed, 17 Sep 2008 17:37:51 +0000, James Kuyper wrote:

    ....
    > > You're right: the standard requires them to have the same alignment
    > > requirements and same representation, but they are not compatible
    > > according to C's definition of the term. This is another of those cases
    > > where the standard falls short of actually saying something that I think
    > > it was actually intended to say. As a practical matter, they work just
    > > as if they were compatible, on most implementations.

    >
    > My compiler reports an error when I try
    >
    > void f(char *p);
    > void f(void *p) {}
    >
    > My compiler doesn't report an error when I try
    >
    > void f(void *p);
    > void f(void *p) {}
    >
    > or when I try
    >
    > void f(int (*p)[]);
    > void f(int (*p)[30]) {}
    >
    > I have trouble believing the intent was to allow the first, or that you
    > believe that was intended. If char * and void * were compatible, it would
    > be allowed, because compatible means something different from how you are
    > using it.


    What I meant is a little more complicated than what I said. You can
    work around the fact that those functions are incompatible by using
    some type punning. The behavior of code that performs such type
    punning is undefined, but I believe that it was the intent of the
    committee that such type punning would work.
     
    , Sep 17, 2008
    #14
  15. On Wed, 17 Sep 2008 13:40:16 -0700, jameskuyper wrote:
    > Harald van Dijk wrote:
    >> On Wed, 17 Sep 2008 17:37:51 +0000, James Kuyper wrote:

    > ...
    >> > You're right: the standard requires them to have the same alignment
    >> > requirements and same representation, but they are not compatible
    >> > according to C's definition of the term. This is another of those
    >> > cases where the standard falls short of actually saying something
    >> > that I think it was actually intended to say. As a practical matter,
    >> > they work just as if they were compatible, on most implementations.

    >>
    >> My compiler reports an error when I try
    >>
    >> void f(char *p);
    >> void f(void *p) {}
    >> [snip]

    >
    > What I meant is a little more complicated than what I said. You can work
    > around the fact that those functions are incompatible by using some type
    > punning. The behavior of code that performs such type punning is
    > undefined, but I believe that it was the intent of the committee that
    > such type punning would work.


    The standard says "The same representation and alignment requirements are
    meant to imply interchangeability as arguments to functions, return values
    from functions, and members of unions." in two footnotes.

    This suggests, for example, that this is valid code (and that g may be
    called):

    void f(void *p) {}
    void g(void) {
    ((void(*)(char *)) f) ("Hello");
    }

    It doesn't actually work though, in at least gcc. But if that is really
    meant to be valid, then I can agree that it is probably the intent to also
    allow

    void *p = 0;
    char *q = *(char **) &p;
     
    Harald van Dijk, Sep 17, 2008
    #15
  16. Guest

    Harald van D©¦k wrote:
    ....
    > The standard says "The same representation and alignment requirements are
    > meant to imply interchangeability as arguments to functions, return values
    > from functions, and members of unions." in two footnotes.


    Yes, that's precisely what I was thinking of. The problem is that it's
    non-normative text. The normative text only requires same
    representation and same alignment requirements. It's possible to
    define function interface conventions that meet those two requirement,
    while not allowing void* and char* to be interchangeable. For
    instance, passing void* return values using a different register than
    char*. Therefore, the standard falls short of actually guaranteeing
    interchangeability.

    > This suggests, for example, that this is valid code (and that g may be
    > called):
    >
    > void f(void *p) {}
    > void g(void) {
    > ((void(*)(char *)) f) ("Hello");
    > }
    >
    > It doesn't actually work though, in at least gcc.


    I'm curious - do you know the details of why it fails? I've known for
    a long time that a lack of interchangeabiltiy is permitted, but it
    would help to be able to cite the details of a real example of it,
    particularly if its a compiler as widely available as gcc.
     
    , Sep 17, 2008
    #16
  17. pete <> writes:
    > wrote:
    >> Harald van D©¦k wrote:
    >> ...
    >>> The standard says "The same representation and alignment requirements are
    >>> meant to imply interchangeability as arguments to functions, return values
    >>> from functions, and members of unions." in two footnotes.

    >>
    >> Yes, that's precisely what I was thinking of. The problem is that it's
    >> non-normative text. The normative text only requires same
    >> representation and same alignment requirements. It's possible to
    >> define function interface conventions that meet those two requirement,
    >> while not allowing void* and char* to be interchangeable. For
    >> instance, passing void* return values using a different register than
    >> char*. Therefore, the standard falls short of actually guaranteeing
    >> interchangeability.

    >
    > The standard would still fall short
    > of actually guaranteeing interchangeability,
    > even if it had been in a normative part of the text
    > instead of in a footnote.
    >
    > If it had been in the normative part of the standard,
    > instead of in a footnote,
    > the question would then be:
    > why does it say
    > "are meant to imply"
    > instead of
    > "imply"?


    Obviously the wording would have to be changed in addition to just
    moving it from the footnote. And dropping "are meant to" wouldn't
    really help; the fact is that the representation and alignment
    requirements *don't* imply interchangeability. There would have to
    be an explicit requirements that the types *are* interchangeable.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 18, 2008
    #17
  18. Chad Guest

    On Sep 16, 2:48 pm, Keith Thompson <> wrote:
    > "" <> writes:
    >
    > [...]
    >
    > > And if that is correct, should we ever use void ** ?

    >
    > void* can be used as a generic pointer type. What that means is that
    > a value of any pointer type (other than a pointer-to-function type)
    > can be converted to void* and back again without loss of information.
    >
    > You might think that void** is therefore a generic pointer-to-pointer
    > type, but it isn't; in fact, there is no generic pointer-to-pointer
    > type.
    >
    > You can convert an int*, or an int**, or an int***, or ... to void*
    > without loss of information -- except that you lose the type
    > information, which you have to carefully keep track of yourself.
    >
    > --


    How would you track the type information in this case?
     
    Chad, Sep 18, 2008
    #18
  19. Keith Thompson <> wrote:
    > ... the fact is that the representation and alignment
    > requirements *don't* imply interchangeability.  There
    > would have to be an explicit requirements that the
    > types *are* interchangeable.


    I'd prefer to see unprototyped functions finally removed
    from C. Then I'd be happy with a statement that functions
    in the standard library that are variadic, or use va_list,
    use va_arg.

    Although, I'd also prefer if va_arg could accept struct
    pointers that are convertable to a common initial sequence,
    but obviously that would imply a greater restriction to
    the language (though I've never seen an implementation
    where it might be an imposition.)

    --
    Peter
     
    Peter Nilsson, Sep 18, 2008
    #19
  20. On Wed, 17 Sep 2008 14:33:26 -0700, jameskuyper wrote:
    > Harald van Dijk wrote:
    > ...
    >> This suggests, for example, that this is valid code (and that g may be
    >> called):
    >>
    >> void f(void *p) {}
    >> void g(void) {
    >> ((void(*)(char *)) f) ("Hello");
    >> }
    >>
    >> It doesn't actually work though, in at least gcc.

    >
    > I'm curious - do you know the details of why it fails?


    test.c: In function ‘g’:
    test.c:3: warning: function called through a non-compatible type
    test.c:3: note: if this code is reached, the program will abort

    When gcc detects that a function is called through an incompatible
    function pointer, and the function definition is available, it rejects the
    call to prevent internal compiler errors when trying if inlining and such
    makes sense. At least, that's how I remember it, but my memory may be off.
     
    Harald van Dijk, Sep 18, 2008
    #20
    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:
    580
    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:
    828
    The Real OS/2 Guy
    Oct 28, 2003
  3. Shawn
    Replies:
    15
    Views:
    1,030
    Shawn
    Dec 14, 2006
  4. Replies:
    5
    Views:
    864
    S.Tobias
    Jul 22, 2005
  5. Replies:
    1
    Views:
    429
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page