Problem with pointer to function - what's wrong here?

C

Charles Sullivan

I define and initialize an array of structures like the following,
(where the <verbiage within angle brackets> is just meant to be
explanatory):

int func1(<argument prototypes>);
int func2(<argument prototypes>);

struct mystruct {
<other stuff>;
int (*myfunc)();
} myrecords[] = {
{<other stuff value>, func1},
{<other stuff value>, NULL },
{<other stuff value>, func2}
};

int func1(<argument list>)
{
<blah-blah-blah1>
}

int func2(<argument list>)
{
<blah-blah-blah2>
}

I've always believed this was legal code, and have used something
similar a few times in the past, but now when (<argument list>) is:
(unsigned char x1, unsigned char x2, unsigned char x3,
int *y1, unsigned int *y2, int *y3)

I get the compiler message:
"warning: initialization from incompatible pointer type"

What am I doing wrong?

Thanks for your help.

Regards,
Charles Sullivan
 
B

Ben Pfaff

Charles Sullivan said:
int (*myfunc)();
[...]

I've always believed this was legal code, and have used something
similar a few times in the past, but now when (<argument list>) is:
(unsigned char x1, unsigned char x2, unsigned char x3,
int *y1, unsigned int *y2, int *y3)

I get the compiler message:
"warning: initialization from incompatible pointer type"

The problem is that there is no way to call a function with that
prototype, through a function pointer without a prototype,
without invoking undefined behavior. The reason is that, when
you invoke a function for which no prototype is available, the
integer promotions are performed on each argument (and arguments
of type float are converted to double). Thus, an "unsigned char"
argument will be converted to and passed as int (or unsigned int
on unusual implementations).

This rule for compatibility of function types is specified, in
C99, in section 6.7.5.3 paragraph 15:

For two function types to be compatible, both shall specify
compatible return types.125) Moreover, ... [if] one type
has a parameter type list and the other type is specified
by a function declarator that is not part of a function
definition and that contains an empty identifier list, the
parameter list shall not have an ellipsis terminator and
the type of each parameter shall be compatible with the
type that results from the application of the default
argument promotions.

It's a rather opaque paragraph, but I'm pretty sure that's what
it means.
 
K

Keith Thompson

Charles Sullivan said:
I define and initialize an array of structures like the following,
(where the <verbiage within angle brackets> is just meant to be
explanatory):

int func1(<argument prototypes>);
int func2(<argument prototypes>);

struct mystruct {
<other stuff>;
int (*myfunc)();
} myrecords[] = {
{<other stuff value>, func1},
{<other stuff value>, NULL },
{<other stuff value>, func2}
};

int func1(<argument list>)
{
<blah-blah-blah1>
}

int func2(<argument list>)
{
<blah-blah-blah2>
}

I've always believed this was legal code, and have used something
similar a few times in the past, but now when (<argument list>) is:
(unsigned char x1, unsigned char x2, unsigned char x3,
int *y1, unsigned int *y2, int *y3)

I get the compiler message:
"warning: initialization from incompatible pointer type"

What am I doing wrong?

I don't believe you've given us enough information to answer that.
Show us some actual code that exhibits the problem. You don't have to
post your actual code (which is probably too big to post); you can
just replace <other stuff> with, say, "int x;", and
"<blah-blah-blah11>" with nothing.
 
D

David T. Ashley

Charles Sullivan said:
I define and initialize an array of structures like the following,
(where the <verbiage within angle brackets> is just meant to be
explanatory):

int func1(<argument prototypes>);
int func2(<argument prototypes>);

struct mystruct {
<other stuff>;
int (*myfunc)();
} myrecords[] = {
{<other stuff value>, func1},
{<other stuff value>, NULL },
{<other stuff value>, func2}
};

int func1(<argument list>)
{
<blah-blah-blah1>
}

int func2(<argument list>)
{
<blah-blah-blah2>
}

I've always believed this was legal code, and have used something
similar a few times in the past, but now when (<argument list>) is:
(unsigned char x1, unsigned char x2, unsigned char x3,
int *y1, unsigned int *y2, int *y3)

I get the compiler message:
"warning: initialization from incompatible pointer type"

What am I doing wrong?

The problem is probably here:
int (*myfunc)();

A modern compiler is going to demand that the input parameters (arguments)
to the function (as defined in the pointer type) be compatible with the
function prototype. I could make arguments based on full prototype linkage
and so on.

Just supply the argument list and I think you'll be OK.
 
E

Eric Sosman

Charles Sullivan wrote On 01/31/07 16:27,:
I define and initialize an array of structures like the following,
(where the <verbiage within angle brackets> is just meant to be
explanatory):

int func1(<argument prototypes>);
int func2(<argument prototypes>);

struct mystruct {
<other stuff>;
int (*myfunc)();
} myrecords[] = {
{<other stuff value>, func1},
{<other stuff value>, NULL },
{<other stuff value>, func2}
};

int func1(<argument list>)
{
<blah-blah-blah1>
}

int func2(<argument list>)
{
<blah-blah-blah2>
}

I've always believed this was legal code, and have used something
similar a few times in the past, but now when (<argument list>) is:
(unsigned char x1, unsigned char x2, unsigned char x3,
int *y1, unsigned int *y2, int *y3)

I get the compiler message:
"warning: initialization from incompatible pointer type"

What am I doing wrong?

Ben Pfaff has explained the error; here are suggestions
for a few fixes.

If all the (<argument prototype>) lists are identical, that's
the easiest case: just change the myfunc declaration inside the
struct to

int (*myfunc)(<argument prototypes>);

and all will be well. ("Identical" in argument count and types;
argument names, if any, don't matter.)

If the prototypes for func1(), func2(), etc. are not the
same, it's a bit harder. In the initializer list, you need to
convert each function pointer to the expected type:

{<other stuff value>, (int(*)())func1},
{<other stuff value>, (int(*)())NULL},
{<other stuff value>, (int(*)())func2},

You could improve the readability by introducing a typedef for
the function pointer casts; also, the cast of NULL isn't really
needed.

But that's not all! At the point where you actually use
the function pointer to call the pointed-to function, you need
to convert it back to the defined type of that called function.
This means you need some way of figuring out what that type is
supposed to be, perhaps with a type code in the <other stuff>.
Then you could write something like

switch (myrecords.type) {
case ONE_INT:
result = ((int(*)(int))myrecords.myfunc)(42);
break;
case TWO_DOUBLES:
result = ((int(*)(double,double))myrecords.myfunc)
(42.0, sqrt(42.0));
break;
...

Again, typedefs might improve the readability.
 
K

Keith Thompson

Keith Thompson said:
Charles Sullivan said:
I define and initialize an array of structures like the following,
(where the <verbiage within angle brackets> is just meant to be
explanatory):

int func1(<argument prototypes>);
int func2(<argument prototypes>);

struct mystruct {
<other stuff>;
int (*myfunc)();
} myrecords[] = {
{<other stuff value>, func1},
{<other stuff value>, NULL },
{<other stuff value>, func2}
}; [snip]
I get the compiler message:
"warning: initialization from incompatible pointer type"

What am I doing wrong?

I don't believe you've given us enough information to answer that.
Show us some actual code that exhibits the problem. You don't have to
post your actual code (which is probably too big to post); you can
just replace <other stuff> with, say, "int x;", and
"<blah-blah-blah11>" with nothing.

I think there was actually enough information to pinpoint the problem;
several other responders saw what I missed.

Posting actual code is still a good idea, though.
 
C

Charles Sullivan

I define and initialize an array of structures like the following,
(where the <verbiage within angle brackets> is just meant to be
explanatory):

int func1(<argument prototypes>);
int func2(<argument prototypes>);

struct mystruct {
<other stuff>;
int (*myfunc)();
} myrecords[] = {
{<other stuff value>, func1},
{<other stuff value>, NULL },
{<other stuff value>, func2}
};

int func1(<argument list>)
{
<blah-blah-blah1>
}

int func2(<argument list>)
{
<blah-blah-blah2>
}

I've always believed this was legal code, and have used something
similar a few times in the past, but now when (<argument list>) is:
(unsigned char x1, unsigned char x2, unsigned char x3,
int *y1, unsigned int *y2, int *y3)

I get the compiler message:
"warning: initialization from incompatible pointer type"

What am I doing wrong?

Many thanks Ben, Keith, David and Eric!

Ben nailed it with his explanation of promoting (which also
clarifies some other unrelated cryptic compiler messages I've
gotten). Thanks Ben.

Keith: Yes, It's good to post actual code, but it can be complex
and confusing unless boiled down to the essentials. Of course I
don't always succeed in identifying the essentials. :)

David and Eric: Thanks for the practical solutions which I will
keep in mind. In this _particular_ case the neatest approach
was to rewrite the functions to make all the arguments int or
int * and do my own conversion back and forth when I call them.

Thanks again guys - the expertise in this newsgroup has once more
restored my sanity!

Regards,
Charles Sullivan
 

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top