warning: dereferencing `void *' pointer

Discussion in 'C Programming' started by Pushkar Pradhan, Dec 14, 2003.

  1. I have some functions which take as i/p a buffer (it can be float, char,
    or 16 bit, int etc.). The result is another o/p buffer, its type is also
    flexible (it could be a float, char etc.).

    I try to pass both as "void *buf" so that it can accept any data type.
    But since I access the buffer and try to assign its elements to another
    I get compile errors (I have pasted at the end).

    Now my question is how can I pass the i/p and o/p buffers as args to the
    function without hardcoding the data type, someone earlier suggested to
    pass another argument which tells the type, e.g.
    myfunction(void * buf, 1, ...) 1 may indicate that buf is char type, 2
    means 16 bit etc.

    But that means having if .. else's inside the function to do the same
    thing. Is there any other way?
    Maybe this is not possible in C.
    Pushkar Pradhan


    resample.c: In function `resample':
    resample.c:26: warning: dereferencing `void *' pointer
    resample.c:26: warning: dereferencing `void *' pointer
    resample.c:26: invalid use of void expression
    resample.c:35: warning: dereferencing `void *' pointer
    resample.c:35: warning: dereferencing `void *' pointer
    resample.c:35: invalid use of void expression
     
    Pushkar Pradhan, Dec 14, 2003
    #1
    1. Advertising

  2. Pushkar Pradhan

    Chris Torek Guest

    In article <>
    Pushkar Pradhan <> writes:
    >I have some functions which take as i/p a buffer (it can be float, char,
    >or 16 bit, int etc.). The result is another o/p buffer, its type is also
    >flexible (it could be a float, char etc.).
    >
    >I try to pass both as "void *buf" so that it can accept any data type.
    >But since I access the buffer and try to assign its elements to another
    >I get compile errors (I have pasted at the end).
    >
    >Now my question is how can I pass the i/p and o/p buffers as args to the
    >function without hardcoding the data type, someone earlier suggested to
    >pass another argument which tells the type, e.g.
    >myfunction(void * buf, 1, ...) 1 may indicate that buf is char type, 2
    >means 16 bit etc.
    >
    >But that means having if .. else's inside the function to do the same
    >thing. Is there any other way?


    Here is a bit pattern, 32 bits long:

    11000101001110101001110101000110

    What does it mean? What value(s) does it represent?

    Does your answer change if I tell you it is the raw bits of a 32-bit
    "float"? What if I say it is a 32-bit VAX float, or perhaps a 32-bit
    SPARC float? Suppose I say it is, instead, a 32-bit "int", or a
    32-bit "signed int". Now what value(s) can it represent? What if
    it is an array of four "char"s or four "unsigned char"s?

    (Finding answers -- there may be more than one -- to the above
    questions is a good and useful exercise, that will help you understand
    how the system(s) you use interpret bits. Note that different
    systems interpret the same bits differently! One reason we use
    "high level" source code -- although C is relatively low level for
    a high level language -- is to avoid having to specify the precise
    set of bits, which change from system to system, when we can get
    away with specifying only what we want the bits to mean. The
    source-code number "3.1415" or "42" has a definite meaning, and
    the fact that machines A and B use different bit-patterns to
    represent them is -- we hope -- irrelevant.)

    Note that all of these are 32 bits long. They all look exactly the
    same when treated as a 32-bit-long bit-string. But they all represent
    different values.

    When you use "void *" in C, you are -- usually -- implicitly using
    a "bag of uninterpreted bits" type. Any interpretation necessarily
    arises from giving the "bag of bits" some more-specific type. You
    must decide whether you intend to interpret the bits, and if so, how.
    This will dictate the type(s) you must provide.

    Note that a series of if/else's, or a switch, inside a function
    that receives a "void *" but wants to interpret the bits as one
    of (say) the two possibilities "int" and "float" will result in C
    code looking like:

    enum whichtype { TY_INT, TY_FLOAT };
    /*
    * Here p points to the first bit(s) in the bag-o-bits, "len"
    * is the number of items of some interpreted type, and "ty"
    * is the enumeration saying which type.
    */
    void f(void *p, size_t len, enum whichtype ty) {
    size_t i;
    int *ip;
    float *fp;

    switch (ty) {
    case TY_INT:
    ip = p;
    ... work with ip, where i is between 0 and len-1, e.g:
    for (i = 0; i < len; i++)
    ip *= 2;
    break;

    case TY_FLOAT:
    fp = p;
    ... work with fp, where i is between 0 and len-1 ...
    for (i = 0; i < len; i++)
    fp *= 2.0;
    break;

    default:
    panic("invalid type argument %d to f()", (int)ty);
    /* NOTREACHED */
    }
    }

    Not only do you really, truly have to write the if/else or switch,
    you will also find that, on typical machines, it compiles to code
    that uses different machine instructions to manipulate the data.
    The code using ip might look like, e.g.:

    # this doubles ip, where i is in %eax and ip is in %edx
    movl (%edx,%eax,4),%ecx
    addl %ecx,%ecx
    movl %ecx,(%edx,%eax,4)

    versus:

    # this doubles fp, where i is in %eax and fp is in %edx
    flds (%edx,%eax,4)
    fadds (%edx,%eax,4)
    fstps (%edx,%eax,4)

    These completely-different machine instructions are utterly necessary
    here -- using the "addl %ecx,%ecx" instructions will not result in
    doubling a "float" value in fp, but rather will just make a mess
    of the value.

    Thus, different C code is required because different machine code
    is required. Using "void *" absolves neither you nor the compiler
    of this.

    If you do enough of this sort of thing (or analyse your systems
    carefully), you will find that there are cases where the C source
    code must be different, yet the underlying machine code on your
    machine(s) is the same. This happens because (and when) the abstract
    meaning defined in C for two different types happens to be implemented
    using a single underlying machine-level mechanism. But in general,
    the C code should remain separate, because on some *other* machine(s),
    this may no longer be the case. In other words, in the C code,
    you write *what* you want to have happen, not *how* to *make* it
    happen. If you want different things, at the C level, that all
    happen to be done the same way at the machine level, it is the
    compiler's job to discover this and optimize the code appropriately.
    (Some compilers are better than others at this, and you may sometimes
    find yourself having to "help" some compilers a bit. Do this only
    when you really know what you are doing. :) )
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, Dec 14, 2003
    #2
    1. Advertising

  3. Pushkar Pradhan

    pete Guest

    Pushkar Pradhan wrote:
    >
    > I have some functions which take as i/p a buffer (it can be float, char,
    > or 16 bit, int etc.). The result is another o/p buffer, its type is also
    > flexible (it could be a float, char etc.).
    >
    > I try to pass both as "void *buf" so that it can accept any data type.
    > But since I access the buffer and try to assign its elements to another
    > I get compile errors (I have pasted at the end).
    >
    > Now my question is how can I pass the i/p and o/p buffers as args to the
    > function without hardcoding the data type, someone earlier suggested to
    > pass another argument which tells the type, e.g.
    > myfunction(void * buf, 1, ...) 1 may indicate that buf is char type, 2
    > means 16 bit etc.
    >
    > But that means having if .. else's inside the function to do the same
    > thing. Is there any other way?
    > Maybe this is not possible in C.


    It depends on exactly what your are trying to do with the buffer.
    If you wanted to do something simple,
    like reverse the order of the elements,
    it could be done this way:

    #include <stddef.h>
    void some_functions(void *buf, size_t nmemb, size_t size)
    {
    unsigned char *first = buf;
    unsigned char *last = (nmemb - 1) * size + first;
    unsigned char *p1, *p2, swap, *end;

    while (last > first) {
    p1 = last;
    p2 = first;
    end = p2 + size;
    do {
    swap = *p1;
    *p1++ = *p2;
    *p2++ = swap;
    } while (p2 != end);
    last -= size;
    first += size;
    }
    }

    If your function is going to do something very different,
    for each different data type that the buffer may contain,
    then you'll need something like a switch;
    perhaps an ifelse tree, or an array of function pointers.

    qsort has this prototype:

    #include <stdlib.h>
    void qsort(void *base, size_t nmemb, size_t size,
    int (*compar)(const void *, const void *));

    The arguments base, nmemb and size,
    tell qsort everything that it needs to know about the array.
    The compar pointer, tells qsort exactly how to deal with the array.

    If your function
    is going to do something different with each data type,
    then you can pass it a function pointer also,
    in a manner similar to the way that one is passed to qsort.

    --
    pete
     
    pete, Dec 14, 2003
    #3
  4. Pushkar Pradhan

    pete Guest

    pete wrote:
    >
    > Pushkar Pradhan wrote:


    > > But since I access the buffer
    > > and try to assign its elements to another


    To do just that one thing,
    first, calculate the total number of bytes,
    and then #include <string.h>, and use memcpy() or memmove().

    --
    pete
     
    pete, Dec 14, 2003
    #4
  5. Pushkar Pradhan

    Guest

    On Sat, 13 Dec 2003 21:24:16 -0600 Pushkar Pradhan <> wrote:
    | I have some functions which take as i/p a buffer (it can be float, char,
    | or 16 bit, int etc.). The result is another o/p buffer, its type is also
    | flexible (it could be a float, char etc.).
    |
    | I try to pass both as "void *buf" so that it can accept any data type.
    | But since I access the buffer and try to assign its elements to another
    | I get compile errors (I have pasted at the end).
    |
    | Now my question is how can I pass the i/p and o/p buffers as args to the
    | function without hardcoding the data type, someone earlier suggested to
    | pass another argument which tells the type, e.g.
    | myfunction(void * buf, 1, ...) 1 may indicate that buf is char type, 2
    | means 16 bit etc.

    Passing them as (void*) should be OK. The problem is in _using_ them as
    (void*). You need to first cast the pointer to the desired type, or assign
    the pointer to a variable defined to have that type. If you are interpreting
    the data as if it were the byte/bit pattern for (double) in your machine's
    (double) format, then cast your pointer to (double*) and dereference. Note
    that some machines will require the alignment be correct and will warn even
    if the alignment really is correct since it might not know what the run time
    really would done. And if it might not be correct, your program could fail.
    In that case you might have to memcpy() the data from the buffer to a variable
    of the correct type. Or you can use a union of mixed types.

    But even if you want to merely copy the data raw without interpreting it,
    you are really still "interpreting" it as characters (in order to step
    through each one by one to do the copy). So you'll need to cast to (char*)
    to do that, or call memcpy() which does it for you (it's arguments are
    (void*) but it treats them as (char*) internally).


    | But that means having if .. else's inside the function to do the same
    | thing. Is there any other way?
    | Maybe this is not possible in C.

    Possible and I have done it many times.

    --
    -----------------------------------------------------------------------------
    | Phil Howard KA9WGN | http://linuxhomepage.com/ http://ham.org/ |
    | (first name) at ipal.net | http://phil.ipal.org/ http://ka9wgn.ham.org/ |
    -----------------------------------------------------------------------------
     
    , Dec 15, 2003
    #5
    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:
    605
    Jack Klein
    Apr 22, 2005
  2. Jun Woong

    Re: dereferencing void *

    Jun Woong, Jul 6, 2003, in forum: C Programming
    Replies:
    0
    Views:
    385
    Jun Woong
    Jul 6, 2003
  3. Stig Brautaset

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

    Stig Brautaset, Oct 25, 2003, in forum: C Programming
    Replies:
    15
    Views:
    839
    The Real OS/2 Guy
    Oct 28, 2003
  4. Replies:
    5
    Views:
    886
    S.Tobias
    Jul 22, 2005
  5. Replies:
    1
    Views:
    439
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page