Can I call a function with pointers of different type?

Discussion in 'C Programming' started by fl, Jan 22, 2012.

  1. fl

    fl Guest

    Hi,
    I have a program which is originally from Matlab mex function. I would
    like to rewrite it in order to run in plain C. The mex interface is a
    Matlab standard. prhs is the call parameter pointer array. Some
    pointers point to array while some point to integer. Matlab uses
    different mxGetPr() to get pointer, or uses mxGetScalar() to get
    value.

    If I write the interface in general C, I try to define prhs as
    pointer's point to integer. If I store some elements of plhs to
    pointers while others to integer, the compiler gives warning. The
    compiler wants prhs as the same level pointers. This kind of warning
    is dangerous or not?

    Another method I think is to use a structer to transfer data to the
    function.

    Do you have some good methods on my question? Thanks.

    ...................
    int **plhs, **prhs;

    prhs = ptr_arr;
    mexFunction(nlhs, plhs, nrhs, prhs);
     
    fl, Jan 22, 2012
    #1
    1. Advertisements

  2. fl

    Eric Sosman Guest

    It is possible that a pointer points to an array, but it is
    very unusual. Are you sure "point to array" is correct? Please
    visit <http://www.c-faq.com/> and read Section 6, or at the very
    least Questions 6.12 and 6.13, and then try again to describe
    exactly what you're doing.
    Probably dangerous, but since you haven't shown us the warning
    or the code that produced it, it's hard to be sure.
    Sorry, but I can't extract much information from this. There
    are two pointer variables, each able to point at a pointer-to-int.
    There's an assignment of ... well, of something unknown, and there's
    a call to a function of unknown type passing unknown arguments. You
    have not provided a lot of clues here ...

    To the question in your Subject: In C, if you call a function
    through a pointer whose type does not match the function's type, the
    effect is undefined. It is likely to work on some systems, and to
    fail mysteriously on others. If it works, it's by coincidence and
    not by design.
     
    Eric Sosman, Jan 22, 2012
    #2
    1. Advertisements

  3. Why not use an array of pointers to void. Then you could have your
    function extract each pointer and convert it to the type it needs to
    be.
     
    Barry Schwarz, Jan 22, 2012
    #3
  4. fl

    gwowen Guest

    The key to MEX is that the types pointed to by plhs and prhs are
    (after suitable indirection) mxArray. This is an opaque type that is
    used to store the data (input/output) but also encodes the *type* of
    data. The mxGetPtr() and mxGetScalar() functions decode the type-
    information and does the right thing. If you need to keep the
    genericity, you'll need to mimic this type-encoding structure in some
    way.
     
    gwowen, Jan 23, 2012
    #4
  5. fl

    Paul N Guest

    I don't think this will necessarily work. As I understand it, there is
    no guarantee that a function pointer will still work if it is
    converted to a void pointer and back.

    However, I think it is allowable to convert any function pointer to
    any other type of function pointer, and this will work correctly as
    long as the compiler knows the correct type of the pointer at the
    point it is used. I'd suggest that the OP creates a typedef for some
    sort of function pointer, and stores his pointers in pointers of that
    type until they are used. The compiler probably won't know what is
    going on and so may issue warnings, but the reader of the code will
    hopefully be able to see what is going on and can see that the
    warnings can safely be ignored.
     
    Paul N, Jan 24, 2012
    #5
  6. Correct. For example, a function pointer might be bigger than void*,
    and converting to void* might lose information. (On a lot of
    implementations, all pointers are the same size, and all pointer
    conversions retain the original value, but the standard doesn't
    guarantee that.)
    Yes, any function pointer can be converted to any other function pointer
    type *and back again*, yielding the original value. Thus, as void* can
    be used as a generic object pointer type, *any* function pointer type
    can be used as a generic function pointer type. (One difference is that
    there are no implicit conversions.)
     
    Keith Thompson, Jan 24, 2012
    #6
  7. fl

    Shao Miller Guest

    (Except when converting to a compatible type.)

    If you're bored, remove all lines containing 'M_ALL_IN_ONE' and split
    into multiple files, or compile all as one .c file.

    #define M_ALL_IN_ONE 1

    /**** funcject.h */
    /*** Types */
    typedef struct incompatible_type * fjret_t;
    typedef fjret_t fj_f();
    typedef fj_f ** fjref_t;
    typedef fj_f * fj_t[1];


    /**** test.h */
    /*** Objects */
    extern fjref_t foo;


    /**** test.c */
    #include <stdio.h>

    #if !M_ALL_IN_ONE
    #include "funcject.h"
    #include "test.h"
    #endif /* M_ALL_IN_ONE */

    /*** Types */
    struct test_funcject;

    /*** Function declarations */
    static void show_state(struct test_funcject *);
    static fj_f test1;
    static fj_f test2;
    static fj_f test3;

    /*** Struct/union definitions */
    struct test_funcject {
    /* Handler */
    fj_t func;
    /* Other stuff */
    int x;
    double y;
    };

    /*** Objects */
    static struct test_funcject my_funcject = { { test1 }, 13, 3.14 };
    fjref_t foo = my_funcject.func;

    /*** Function definitions */
    static void show_state(struct test_funcject * this) {
    printf("We have: %d and %f\n", this->x, this->y);
    return;
    }

    /* Actual definition compatible with above declaration */
    static fjret_t test1(fj_t fj) {
    struct test_funcject * const this = (void *) fj;

    puts("test1():");
    show_state(this);
    this->func[0] = test2;
    puts("test1() complete.\n");
    return 0;
    }

    /* Actual definition compatible with above declaration */
    static fjret_t test2(fj_t fj, int x) {
    struct test_funcject * const this = (void *) fj;

    puts("test2():");
    show_state(this);
    this->x = x;
    puts("I just set x");
    show_state(this);
    this->func[0] = test3;
    puts("test2() complete.\n");
    return 0;
    }

    /* Actual definition compatible with above declaration */
    static fjret_t test3(fj_t fj, double y) {
    struct test_funcject * const this = (void *) fj;

    puts("test3():");
    show_state(this);
    this->y = y;
    puts("I just set y");
    show_state(this);
    this->func[0] = test1;
    puts("test3() complete.\n");
    return 0;
    }


    /**** main.c */
    #if !M_ALL_IN_ONE
    #include "funcject.h"
    #include "test.h"
    #endif /* M_ALL_IN_ONE */

    int main(void) {
    /* Pretend all we know about is 'foo' */
    (*foo)(foo);
    (*foo)(foo, 42);
    (*foo)(foo, 13.42);
    (*foo)(foo);
    (*foo)(foo, 99);
    (*foo)(foo, 99.99);
    return 0;
    }
     
    Shao Miller, Jan 25, 2012
    #7
    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.