pointer to function being casted as a struct?

Discussion in 'C Programming' started by dmjcunha, Feb 14, 2014.

  1. dmjcunha

    dmjcunha Guest

    Hi, I am studying a code but I am having difficulties...
    Here it is:

    struct drm_driver_descriptor
    {
    const char *name;
    const char *driver_name;
    struct pipe_screen* (*create_screen)(int drm_fd);
    const struct drm_conf_ret *(*configuration) (enum drm_conf conf);
    };

    extern struct drm_driver_descriptor driver_descriptor;

    typedef void (*func_pointer)(void);

    static INLINE func_pointer
    pointer_to_func( void *p )
    {
    union {
    void *p;
    func_pointer f;
    } pf;
    pf.p = p; /*pf.f has no attribution*/
    return pf.f;
    }

    dd = (const struct drm_driver_descriptor *) pointer_to_func(dlsym(library, "driver_descriptor"); /*here how could pointer_to_func which returns func_pointer which is not attributed to anything be casted to struct drm_driver_descriptor?*/

    And latter there is code like: dd->create_screen(...);
    How could it be so?
    Thanks in advance.
     
    dmjcunha, Feb 14, 2014
    #1
    1. Advertisements

  2. dmjcunha

    James Kuyper Guest

    I'm not sure what you mean by "attributed to anything".
    That code contains no casts; it uses a union to reinterpret memory.

    There is a function named dlsym() that is provided as part of POSIX.
    I'll presume that you're talking about either that function or a close
    equivalent. C itself does not guarantee that sizeof pf.p == sizeof pf.f,
    and makes no promises that loading pf.f with a function pointer value
    leaves pf.p with a valid void* value, or vice versa. However, POSIX
    requires that dlsym's return value be usable in that fashion, which
    requires that those things be true, even though the C standard allows
    them to not be true.

    In particular, the internals of dlsym could be something as follows:

    void *dlsym(void *handle, const char *symbol)
    {
    union {
    void *p;
    func_pointer f;
    } pf;
    // Use handle to locate the function or object identified by
    // symbol.
    if(handle_invalid || symbol_not_found)
    return NULL;
    if(symbol_refers_to_a_function)
    pf.f = an_expression_pointing_to_that_function;
    else
    pf.p = an_expression_pointing_to_that_object;
    return pf.p;
    }

    Note: in the actual code, pf need not be a union, and the equivalent of
    the if() statement is actually probably a simple memcpy(&pf,
    somewhere_else, sizeof pf), which works fine, only because POSIX
    guarantees it works fine.

    Do you understand, given what POSIX guarantees about the compatibility
    of pointers to functions and objects, why the above code could produce
    results compatible with the way the code you are reading was written?
     
    James Kuyper, Feb 14, 2014
    #2
    1. Advertisements

  3. What do you mean by no attribution? pf.f has type pointer to function
    taking one argument (of type pointer to void) and not returning any
    value (sometimes expressed as returning void). As a result of this
    assignment, it also has a value. What that value is and whether it is
    valid or not is system dependent. Given that pf.f and pf.p may have
    different sizes, all we can say is that corresponding bits which are
    common to both have the same value.

    If pf.p is shorter than pf.f, the extra bits in pf.f are
    indeterminate. If the opposite, then the extra bits in pf.p are
    ignored in the return statement that follows. Even if they are the
    same size, there is no guarantee that the bit pattern of the parameter
    p (which is what is stored in pf.p) are a legal pattern when evaluated
    as the value of a pointer to function (which is the type of pf.f used
    in the return statement). It could be trap representation.
    Since this statement has unbalanced parentheses, you probably typed it
    in manually. You should really use cut and paste to preserve the
    accuracy of the code in question.

    What do you mean by attributed? From the code in this statement, it
    appears that dlsym returns a pointer value. That value is either a
    pointer to void (in which case it is passed directly to
    pointer_to_func) or a pointer to some object type (in which case it is
    implicitly converted to pointer to void and the converted value passed
    to pointer_to_func). In both cases, pointer_to_func receives a void*
    value and returns a pointer to function value. The cast operator then
    converts that pointer to function value to pointer to structure value.
    AT NO TIME IS THE POINTER VALUE CONVERTED TO A STRUCT VALUE. The
    pointer value is converted from one type of pointer to another type of
    pointer. This particular conversion between a function to pointer and
    a function to object is something the standard does not describe.
    Consequently, unless your system documents what this conversion is,
    the code is relying on unspecified (or possibly undefined) behavior.

    The sample you provided makes no sense since the conversion could be
    performed much more simply with
    dd = (const struct drm_driver_descriptor *)
    dlsym(library, "driver_descriptor");
    There is no need for an intermediate conversion to a function pointer
    when converting between to types of object pointers.
    How could what be so? dd is a pointer to structure. create_screen is
    a member of that structure. Somewhere in the code you did not show
    that member is assigned a value (the address of a function). This
    code simply calls that function. The -> operator is the correct tool
    to access the member of a structure when you have the address of that
    structure.
     
    Barry Schwarz, Feb 14, 2014
    #3
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.