While writing code for a "file descriptor" which imposes an array of function pointers, i stumbled over a "problem" which i first thought was an error in sdcc. In order to report the error i simplified the source until it only consisted of these 4 lines:
typedef int (*MyFPtr)(struct Data*); struct Data { int a; }; extern int bar(struct Data* f); MyFPtr foo = bar;
➜ I make a typedef for a function pointer, because function pointers are so awkward in c (though they are a pretty compared to function pointers in c++ ... which resulted in the invention of the data type 'auto' ...)
Then at some point i actually define the struct.
Later i declare a function which matches the typedef.
Finally i try to assign this function to a function pointer variable.
compiling this source resulted in an error for the last line:
/foo-1.c:4: error 78: incompatible types from type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed' to type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed' /foo-1.c:5: error 78: incompatible types from type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed' to type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed'
btw.: ignore the double error. Error messages in sdcc are always a little bit suboptimal.
This looked as if the compiler had a problem to see that too identical types are identical.
And indeed they aren't.
As i learned from my bug report, the first line implicitly declares a local data type. Local to – yes, i don't know exactly to what. But it's local. And so it's different to the later and globally defined struct.
One suggested solution was:
typedef unsigned int (*T)(struct Data*); extern unsigned int foo(struct Data* f); T bar = foo;
which compiled without error. But this now was actually an error in sdcc: This source is wrong too:
Line 1 and 2 both declare local data types which by that are different. Line 3 shouldn't work. That there was an error could be proved by actually trying to use the function pointer typedef:
typedef unsigned int (*T)(struct Data*); // local data type extern unsigned int foo(struct Data* f); // local data type T bar = foo; // works in sdcc but shouldn't struct Data { unsigned int a; }; int main() { struct Data d = {0}; foo(&d); } // rejected
This lead me to the question:
For what is the implicit declaration of a local data type in a function's argument list good, anyway? I can't think of a real use case. It's near impossible to call such a function. You have to cast the function to a function which accepts the data type you actually have, because you cannot even cast your data to the local data type...
Second, it's just a pitfall: If you declared the data type before the typedef and before the function declaration or definition, then the global data type is used. If you didn't, then a local data type is used. Imagine a local variable a in a function body was local only if there was no global variable a defined before…
No comments:
Post a Comment