Is it legal to cast function pointers? [duplicate] - c++

Let's say I have a function that accepts a void (*)(void*) function pointer for use as a callback:
void do_stuff(void (*callback_fp)(void*), void* callback_arg);
Now, if I have a function like this:
void my_callback_function(struct my_struct* arg);
Can I do this safely?
do_stuff((void (*)(void*)) &my_callback_function, NULL);
I've looked at this question and I've looked at some C standards which say you can cast to 'compatible function pointers', but I cannot find a definition of what 'compatible function pointer' means.

As far as the C standard is concerned, if you cast a function pointer to a function pointer of a different type and then call that, it is undefined behavior. See Annex J.2 (informative):
The behavior is undefined in the following circumstances:
A pointer is used to call a function whose type is not compatible with the pointed-to
type (6.3.2.3).
Section 6.3.2.3, paragraph 8 reads:
A pointer to a function of one type may be converted to a pointer to a function of another
type and back again; the result shall compare equal to the original pointer. If a converted
pointer is used to call a function whose type is not compatible with the pointed-to type,
the behavior is undefined.
So in other words, you can cast a function pointer to a different function pointer type, cast it back again, and call it, and things will work.
The definition of compatible is somewhat complicated. It can be found in section 6.7.5.3, paragraph 15:
For two function types to be compatible, both shall specify compatible return types127.
Moreover, the parameter type lists, if both are present, shall agree in the number of
parameters and in use of the ellipsis terminator; corresponding parameters shall have
compatible types. 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. If one type has a parameter type list and the other type is
specified by a function definition that contains a (possibly empty) identifier list, both shall
agree in the number of parameters, and the type of each prototype parameter shall be
compatible with the type that results from the application of the default argument
promotions to the type of the corresponding identifier. (In the determination of type
compatibility and of a composite type, each parameter declared with function or array
type is taken as having the adjusted type and each parameter declared with qualified type
is taken as having the unqualified version of its declared type.)
127) If both function types are ‘‘old style’’, parameter types are not compared.
The rules for determining whether two types are compatible are described in section 6.2.7, and I won't quote them here since they're rather lengthy, but you can read them on the draft of the C99 standard (PDF).
The relevant rule here is in section 6.7.5.1, paragraph 2:
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
Hence, since a void* is not compatible with a struct my_struct*, a function pointer of type void (*)(void*) is not compatible with a function pointer of type void (*)(struct my_struct*), so this casting of function pointers is technically undefined behavior.
In practice, though, you can safely get away with casting function pointers in some cases. In the x86 calling convention, arguments are pushed on the stack, and all pointers are the same size (4 bytes in x86 or 8 bytes in x86_64). Calling a function pointer boils down to pushing the arguments on the stack and doing an indirect jump to the function pointer target, and there's obviously no notion of types at the machine code level.
Things you definitely can't do:
Cast between function pointers of different calling conventions. You will mess up the stack and at best, crash, at worst, succeed silently with a huge gaping security hole. In Windows programming, you often pass function pointers around. Win32 expects all callback functions to use the stdcall calling convention (which the macros CALLBACK, PASCAL, and WINAPI all expand to). If you pass a function pointer that uses the standard C calling convention (cdecl), badness will result.
In C++, cast between class member function pointers and regular function pointers. This often trips up C++ newbies. Class member functions have a hidden this parameter, and if you cast a member function to a regular function, there's no this object to use, and again, much badness will result.
Another bad idea that might sometimes work but is also undefined behavior:
Casting between function pointers and regular pointers (e.g. casting a void (*)(void) to a void*). Function pointers aren't necessarily the same size as regular pointers, since on some architectures they might contain extra contextual information. This will probably work ok on x86, but remember that it's undefined behavior.

I asked about this exact same issue regarding some code in GLib recently. (GLib is a core library for the GNOME project and written in C.) I was told the entire slots'n'signals framework depends upon it.
Throughout the code, there are numerous instances of casting from type (1) to (2):
typedef int (*CompareFunc) (const void *a,
const void *b)
typedef int (*CompareDataFunc) (const void *b,
const void *b,
void *user_data)
It is common to chain-thru with calls like this:
int stuff_equal (GStuff *a,
GStuff *b,
CompareFunc compare_func)
{
return stuff_equal_with_data(a, b, (CompareDataFunc) compare_func, NULL);
}
int stuff_equal_with_data (GStuff *a,
GStuff *b,
CompareDataFunc compare_func,
void *user_data)
{
int result;
/* do some work here */
result = compare_func (data1, data2, user_data);
return result;
}
See for yourself here in g_array_sort(): http://git.gnome.org/browse/glib/tree/glib/garray.c
The answers above are detailed and likely correct -- if you sit on the standards committee. Adam and Johannes deserve credit for their well-researched responses. However, out in the wild, you will find this code works just fine. Controversial? Yes. Consider this: GLib compiles/works/tests on a large number of platforms (Linux/Solaris/Windows/OS X) with a wide variety of compilers/linkers/kernel loaders (GCC/CLang/MSVC). Standards be damned, I guess.
I spent some time thinking about these answers. Here is my conclusion:
If you are writing a callback library, this might be OK. Caveat emptor -- use at your own risk.
Else, don't do it.
Thinking deeper after writing this response, I would not be surprised if the code for C compilers uses this same trick. And since (most/all?) modern C compilers are bootstrapped, this would imply the trick is safe.
A more important question to research: Can someone find a platform/compiler/linker/loader where this trick does not work? Major brownie points for that one. I bet there are some embedded processors/systems that don't like it. However, for desktop computing (and probably mobile/tablet), this trick probably still works.

The point really isn't whether you can. The trivial solution is
void my_callback_function(struct my_struct* arg);
void my_callback_helper(void* pv)
{
my_callback_function((struct my_struct*)pv);
}
do_stuff(&my_callback_helper);
A good compiler will only generate code for my_callback_helper if it's really needed, in which case you'd be glad it did.

You have a compatible function type if the return type and parameter types are compatible - basically (it's more complicated in reality :)). Compatibility is the same as "same type" just more lax to allow to have different types but still have some form of saying "these types are almost the same". In C89, for example, two structs were compatible if they were otherwise identical but just their name was different. C99 seem to have changed that. Quoting from the c rationale document (highly recommended reading, btw!):
Structure, union, or enumeration type declarations in two different translation units do not formally declare the same type, even if the text of these declarations come from the same include file, since the translation units are themselves disjoint. The Standard thus specifies additional compatibility rules for such types, so that if two such declarations are sufficiently similar they are compatible.
That said - yeah strictly this is undefined behavior, because your do_stuff function or someone else will call your function with a function pointer having void* as parameter, but your function has an incompatible parameter. But nevertheless, i expect all compilers to compile and run it without moaning. But you can do cleaner by having another function taking a void* (and registering that as callback function) which will just call your actual function then.

As C code compiles to instruction which do not care at all about pointer types, it's quite fine to use the code you mention. You'd run into problems when you'd run do_stuff with your callback function and pointer to something else then my_struct structure as argument.
I hope I can make it clearer by showing what would not work:
int my_number = 14;
do_stuff((void (*)(void*)) &my_callback_function, &my_number);
// my_callback_function will try to access int as struct my_struct
// and go nuts
or...
void another_callback_function(struct my_struct* arg, int arg2) { something }
do_stuff((void (*)(void*)) &another_callback_function, NULL);
// another_callback_function will look for non-existing second argument
// on the stack and go nuts
Basically, you can cast pointers to whatever you like, as long as the data continue to make sense at run-time.

Well, unless I understood the question wrong, you can just cast a function pointer this way.
void print_data(void *data)
{
// ...
}
((void (*)(char *)) &print_data)("hello");
A cleaner way would be to create a function typedef.
typedef void(*t_print_str)(char *);
((t_print_str) &print_data)("hello");

If you think about the way function calls work in C/C++, they push certain items on the stack, jump to the new code location, execute, then pop the stack on return. If your function pointers describe functions with the same return type and the same number/size of arguments, you should be okay.
Thus, I think you should be able to do so safely.

Void pointers are compatible with other types of pointer. It's the backbone of how malloc and the mem functions (memcpy, memcmp) work. Typically, in C (Rather than C++) NULL is a macro defined as ((void *)0).
Look at 6.3.2.3 (Item 1) in C99:
A pointer to void may be converted to or from a pointer to any incomplete or object type

Related

How does void* work as a universal reference type?

From Programming Language Pragmatics, by Scott
For systems programming, or to facilitate the writing of
general-purpose con- tainer (collection) objects (lists, stacks,
queues, sets, etc.) that hold references to other objects, several
languages provide a universal reference type. In C and C++, this
type is called void *. In Clu it is called any; in Modula-2,
address; in Modula-3, refany; in Java, Object; in C#, object.
In C and C++, how does void * work as a universal reference type?
void * is always only a pointer type, while a universal reference type contains all values, both pointers and nonpointers. So I can't see how void * is a universal reference type.
Thanks.
A void* pointer will generally hold any pointer that is not a C++ pointer-to-member. It's rather inconvenient in practice, since you need to cast it to another pointer type before you can use it. You also need to convert it to the same pointer type that it was converted from to make the void*, otherwise you risk undefined behavior.
A good example would be the qsort function. It takes a void* pointer as a parameter, meaning it can point to an array of anything. The comparison function you pass to qsort must know how to cast two void* pointers back to the types of the array elements in order to compare them.
The crux of your confusion is that neither an instance of void * nor an instance of Modula-3's refany, nor an instance of any other language's "can refer to anything" type, contains the object that it refers to. A variable of type void * is always a pointer and a variable of type refany is always a reference. But the object that they refer to can be of any type.
A purist of programming-language theory would tell you that C does not have references at all, because pointers are not references. It has a nearly-universal pointer type, void *, which can point to an object of any type (including integers, aggregates, and other pointers). As a common but not ubiquitous extension, it can also point to any function (functions are not objects).
The purist would also tell you that C++ does not have a (nearly-)universal pointer type, because of its stricter type system, and doesn't have a universal reference type either.
They would also say that the book you are reading is being sloppy with its terminology, and they would caution you to not take any one such book for the gospel truth on terminological matters, or any other matters. You should instead read widely in both books and CS journals and conference proceedings (collectively known as "the literature") until you gain an "ear" for what is generally-agreed-on terminology, what is specific to a subdiscipline or a community of practice, and so on.
And finally they would remind you that C and C++ are two different languages, and anyone who speaks of them in the same breath is either glossing over the distinctions (which may or may not be relevant in context), decades out of date, or both.
Probably the reason is that you can take address of any variable of any type and cast it to void*.
It does by a silent contract that you know the actual type of object.
So you can store different kinds of elements in a container, but you need to somehow know what is what when taking elements back, to interpret them correctly.
The only convenience void* offers is that it's idiomatic for this, i.e. it's clear that dereferencing the pointer makes no sense, and void* is implicitly convertible to any pointer type. That is for c/
In c++ this is called type erasure techniques preferred. Or special types, like any (there is a boost version of this too.)
void* is no more just a pointer. Thus, it holds an address of an object (or an array and stuffs like that)
When your program is running, every variable should have it owns address in memory, right? And pointer is somethings point to that address.
In normal, each type of pointer should be the same type of object int b = 5; int* p = &b; for example. But that is the case you know what the type is, it means the specific type.
But sometimes, you just want to know that it stores somethings somewhere in memory and you know what "type" of that address, you can cast easily. For example, in OpenCV library which I am learning, there are a lot of functions where user can pass the arguments to instead of declaring global variables and most use in callback functions, like this:
void onChange(int v, void *ptr)
Here, the library does not care about what ptr point to, it just know that when you call the function, if you pass an address to like this onChange(5,&b) then you must cast ptr to the same type before dealing with it int b = static_cast<int*>(ptr);
Probably this explanation from Understanding pointers from Richard Reese will help
A pointer to void is a general-purpose pointer used to hold references to any data type.
It has two interesting properties:
A pointer to void will have the same representation and memory alignment as a pointer to char
A pointer to void will never be equal to another pointer. However, two void pointers assigned a NULL value will be equal.
Any pointer can be assigned to a pointer to void. It can then be cast back to its original pointer type. When this happens the value will be equal to the original pointer value.
This is illustrated in the following sequence, where a pointer to
int is assigned to a pointer to void and then back to a pointer to int
#include<stdio.h>
void main()
{
int num = 100;
int *pi = &num;
printf("value of pi is %p\n", pi);
void* pv = pi;
pi = (int*)pv;
printf("value of pi is %p\n", pi);
}
Pointers to void are used for data pointers, not function pointers

Do C interfaces care about the pointed-to type?

I have two pieces of code: The first, inside a C++ program, is where I load and call a function from an external test_lib.so:
typedef void *(*init_t)(); // init_t is ptr to fcn returning a void*
typedef void (*work_t)(void *); // work_t is ptr to fcn taking a void*
void *lib = dlopen("test_lib.so", RTLD_NOW);
init_t init_fcn = dlsym(lib, "test_fcn");
work_t work_fcn = dlsym(lib, "work_fcn");
void *data = init_fcn();
work_fcn(data);
The second piece of code is the one that compiles to test_lib.so:
struct Data {
// ...
};
extern "C" {
void *init_fcn() {
Data *data = new Data; // generate a new Data*...
return data; // ...and return it as void*
}
void work_fcn(void *data) { // take a void*...
static_cast<Data *>(data)->blabla(); // ...and treat it as Data*
static_cast<Data *>(data)->bleble();
}
}
Now, the first piece of code doesn't need to know what Data is, it just passes the pointer around, so it's a void*. But the library, which works directly with data's methods and members, needs to know, so it must convert the void*s to Data*s.
But the interface between the two pieces of code is just some functions with pointer arguments and/or return types. I could just keep the void* in the client, and change every instance of void* in the library to Data*. I did that, and everything works fine (my system is Linux/GCC 6.2.1).
My question is: was I lucky, or is this guaranteed to work everywhere? If I'm not mistaken, the result of calling some f(Data*) with a void* argument is just as if called reinterpret_cast<Data*> on the void* --- and that couldn't possibly be dangerous. Right?
EDIT: No, simply making the Data type transparent to the client code won't work. The client code calls many libraries through the same API, but each library might have its own implementation. For the client, Data could be anything.
Calling any function through the wrong function type is automatically undefined behavior. From C++ Standard draft n4604 (roughly C++17) [expr.reinterpret.cast]:
A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling a function through a pointer to a function type that is not the same as the type used in the definition of the function is undefined. Except that converting a prvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are function types) and back to its original type yields the original pointer value, the
result of such a pointer conversion is unspecified.
Calling any function through a function pointer type with the wrong linkage is also undefined behavior. Your typedefs don't use "C" linkage, ergo UB. From draft n4604 section [expr.call]:
Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function’s definition is undefined.
Besides that point, different pointer types are not required to have the same representation. (cv-qualified) void* can hold any object pointer, but its alignment restrictions are the same as char* (that is, no restriction) and as a result, it's not necessarily representation compatible with other object pointer types and may not even be the same size. (And most definitely, object pointers, function pointers, and the variations on pointer-to-member are frequently different sizes on real-world systems.)
While this is likely to work in practice, C doesn't guarantee this behavior.
There are two problems:
Different pointer types can have different sizes and representations. On such an implementation going to void * and back involves an actual conversion at runtime, not just a cast to make the compiler happy. See http://c-faq.com/null/machexamp.html for a list of examples, e.g. "The old HP 3000 series uses a different addressing scheme for byte addresses than for word addresses; like several of the machines above it therefore uses different representations for char * and void * pointers than for other pointers."
Different pointer types can use different calling conventions. For example, an implementation might pass void * on the stack but other pointers in registers. C doesn't define an ABI, so this is legal.
That said, you're using dlsym, which is a POSIX function. I don't know if POSIX imposes additional requirements that make this code portable (to all POSIX systems).
On the other hand, why don't you use Data * everywhere? On the client side you can just do
struct Data;
to leave the type opaque. This fulfills your original requirements (the client can't mess with the internals of Data because it doesn't know what it is, it can only pass pointers around), but also makes the interface a bit safer: You can't accidentally pass the wrong pointer type to it, which would be silently accepted by something taking void *.
You can make it cleaner by using opaque structure definitions. See the second half of the accepted answer here:
Why should we typedef a struct so often in C?
Thus the caller is handling pointers to a defined type, but cannot see inside what is being pointed at. The implementation has the actual struct definition, and can work with it. No more casting is required.

Are void* pointer and pointer to some structure (layout-) compatible?

In other words, may I reinterpret (not convert!) void* pointer as a pointer to some structure type (assuming that the void* pointer really holds properly converted valid structure address)
Actually I'm interesting in the following scenario:
typedef struct void_struct void_struct_t;
typedef somestruct
{
int member;
// ... other members ...
}somestruct_t;
union
{
void* pv;
void_struct_t* pvs;
somestruct_t* ps;
}u;
somestruct_t s={};
u.pv= &s;
u.ps->member=1; // (Case 1) Ok? unspecified? UB?
u.pvs=(void_struct_t*)&s;
u.ps->member=1; // (Case 2) )Ok?
What I found in the C11 standard is rather dissapointing for the Case 1:
§6.2.5
28 A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type.[footnote: The same representation and alignment requirements
are meant to imply interchangeability as arguments to functions, return values from
functions, and members of unions.] Similarly, pointers to qualified or unqualified
versions of compatible types shall have the same representation and alignment
requirements. All pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types shall have the same
representation and alignment requirements as each other. Pointers to other types need not
have the same representation or alignment requirements.
It seems, though, that Case 2 is valid, but I'm not 100% sure...
The question is mostly C-oriented, but I'm interesting in C++ too (I'd want the code would be valid while compiling by C++ compiler). Honestly, I found even less in C++11 standard, so even Case 2 seems questionable for me... however, may be I'm missing something.
[edit]
What is the real problem behind this question?
I have a (potentially large) set of types defined as structs.
For each type I need to define a companion type:
typedef struct companion_for_sometype
{
sometype* p_object;
// there are also other members
}companion_for_sometype;
Obviously, the companion type would be a template in C++, but I need a solution for C
(more exactly, for "clean C", i.e for intersection of C89 and C++ as I want my code to be also valid C++ code).
Fortunately, it is not a problem even in C, since I can define a macro
DECLARE_COMPANION(type_name) typedef struct companion_for_##type_name
{
type_name* p_object;
// there are also other members
}companion_for_##type_name;
and just invoke it for every type that need a companion.
There is also a set of generic operations on companion types.
These operations are also defined by macros (since there are no overloads in pure C).
One of this operations, say
#define op(companion_type_object) blablabla
should assign a void* pointer to p_object field of the companion object,
i.e. should do something like this:
(companion_type_object).p_object= (type_name*) some_function_returning_pvoid(..)
But the macro doesn't know type_name (only an object of companion type is passed to the macro)
so the macro can't do the appropriate pointer cast.
The question is actually inspired by this problem.
To solve it, I decide to reinterpret target pointer in the assignment as void* and then assign to it.
It may be done by replacing the pointer in the companion declaration with a union of pointers
(the question is about this case), or one may reinterpret target pointer directly, say:
*(void**) &(companion_type_object).p_object= some_function_returning_pvoid(..)
But I can't find any solution without reinterpreting pointers (maybe I'm missing some possibilities though)
void * is a pointer that can hold any object pointer type, that includes all pointers to structure type. So you can assign any pointer to a structure type to a void *.
But void * and pointers to structure types are not guaranteed to have the same representation so your case 1 is undefined behavior.
(C11, 6.2.5p28) "[...] Pointers to other types need not have the same
representation or alignment requirements."
In C, void * automatically casts to any object type, so this will work:
(companion_type_object).p_object = some_function_returning_pvoid(..)
In C++, you need to use static_cast, but you can find out the required type using decltype :
(companion_type_object).p_object =
static_cast<decltype(*(companion_type_object).p_object) *>(
some_function_returning_pvoid(..))
In C++03 you should be able to use some compiler extension equivalent to decltype. Alternatively, you could provide a macro-generated method on companion_type_object to cast a void * to the appropriate type:
static type_name *void_p_to_object_p(void *p) { return static_cast<type_name *>(p); }
...
(companion_type_object).p_object = companion_type_object.void_p_to_object_p(
some_function_returning_pvoid(..))

How can I get rid of this reinterpret_cast, or is this usage OK?

I have a template member function with this signature:
template<typename T> void sync(void (*work)(T*), T context);
It can be called with a pointer to a function that accepts an argument of type T*. context is passed to that function. The implementation is this:
template<typename T> void queue::sync(void (*work)(T*), T context) {
dispatch_sync_f(_c_queue, static_cast<void*>(&context),
reinterpret_cast<dispatch_function_t>(work));
}
It uses reinterpret_cast<> and it works. The problem is that the standard doesn't define it very well and it is very dangerous. How can I get rid of this? I tried static_cast but that gave me a compiler error:
static_cast from void (*)(std::__1::basic_string<char> *) to dispatch_function_t (aka void (*)(void *)) is not allowed.
dispatch_function_t is a C type and is the same as void (*)(void*).
I'm not sure I was clear enough. What dispatch_sync_f does is it calls a given callback function and passes the given context parameter to that callback function. (It does that on another thread, although that is out of the scope of this question.)
The reason this is not supported by static_cast is because it is
potentially unsafe. While a std::string* will convert implicitely to
a void*, the two are not the same thing. The correct solution is to
provide a simple wrapper class to your function, which takes a void*,
and static_casts it back to the desired type, and pass the address of
this wrapper function to your function. (In practice, on modern
machines, you'll get away with the reinterpret_cast, since all
pointers to data have the same size and format. Whether you want to cut
corners like this is up to you—but there are cases where it's
justified. I'm just not convinced that this is one of them, given the
simple work-around.)
EDIT: One additional point: you say that dispatch_function_t is a C type. If this is the case, the actual type if probably extern "C" void (*)(void*), and you can only initialize it with functions that have "C" linkage. (Again, you're likely to get away with it, but I've used compilers where the calling conventions were different for "C" and "C++".)
I guess, you are not only casting work to dispatch_function_t, but calling it through dispatch_function_t pointer, aren't you? Such cast itself is valid according to standard, but all you can do with a casted pointer is cast it back to original type. Still your approach should work with most compilers and platforms. If you'd like to implement it so it's more standard conforming you can make a wrapper for your context and work function like this:
template <typename T>
struct meta_context_t
{
T *context;
void (*work)(T*);
};
template <typename T>
void thunk(void *context)
{
meta_context_t<T> *meta_context = static_cast<meta_context_t<T> *>(context);
meta_context->work(meta_context->context);
}
template<typename T> void queue::sync(void (*work)(T*), T context) {
meta_context_t<T> meta_context =
{
&context,
work
};
dispatch_sync_f(_c_queue, static_cast<void*>(&meta_context),
thunk<T>);
}
I can't believe this works or you have a rather narrow definition of "this works" (e.g. you found one particular setup where it seems to do what you think it should do). I'm not clear what dispatch_sync_f() does but I think it is suspicious that it gets a pointer to the local variable context as parameter. Assuming this variable outlives the use of this pointer, there is still a subtle problem which won't get you on most platforms but does get you on some:
C and C++ calling conventions can be different. That is, you cannot cast a pointer to a C++ function to a pointer to a C function and hope for this to be callable. The fix to this problem - and your original question - is, of course, an extra level of indirection: don't dispatch to the function you get as argument but rather dispatch to a C function (i.e. a C++ function declared as extern "C") which takes its own context holding both the original context and the original function and calls the original function. The only [explicit] cast needed is the static_cast<>() restoring a pointer to your internal context from the void*.
Since you seem to implement a template you might need to use another indirection to get rid of this type: I don't thing function templates can be declared extern "C". So you would need to restore the original type somehow e.g. using a base class and a virtual function or something like std::function<void()> holding a readily callable function object doing this conversion (a pointer to this object would be your context).
I believe the cast to/from these two function pointer types is fine:
void(*)(void*)
void(*)(T*)
The problem is that you can't actually use the pointer that you have so cast. It's legal only to cast back to the original type (and those casts are reinterpret_cast, because these are unrelated types). From your code, I can't see how your actual callback function is defined. Why can't you accept a dispatch_function_t as your parameter for queue::sync, rather than casting it?
reinterpret_cast is guaranteed to work when converting from a type T * to void * and back. It is, however, not acceptable to cast from or to a pointer to a base or derived class of T.
The type of work needs to be dispatch_function_t in this case, and the first order of business in that function needs to be the cast from void * to T *. Implicitly casting the argument by using a different argument type and casting the function type is not allowed.
Rationale: the standard allows different pointer representations for different types, as long as all pointer types can be converted to void * and back, so void * is the "most precise" pointer type. A conforming implementation is allowed to clear the bottom-order bits of an uint32_t * if sizeof(uint32_t) > sizeof(char) (i.e. sizeof(uint32_t) > 1) or even shift the pointer value if the machine instructions can utilize these pointers more effectively; on a machine with tagged or shifted pointer values the reinterpret_cast is not necessarily a no-op and needs to be written explicitly.

Why can't arrays be passed as function arguments?

Why can't you pass arrays as function arguments?
I have been reading this C++ book that says 'you can't pass arrays as function arguments', but it never explains why. Also, when I looked it up online I found comments like 'why would you do that anyway?' It's not that I would do it, I just want to know why you can't.
Why can't arrays be passed as function arguments?
They can:
void foo(const int (&myArray)[5]) {
// `myArray` is the original array of five integers
}
In technical terms, the type of the argument to foo is "reference to array of 5 const ints"; with references, we can pass the actual object around (disclaimer: terminology varies by abstraction level).
What you can't do is pass by value, because for historical reasons we shall not copy arrays. Instead, attempting to pass an array by value into a function (or, to pass a copy of an array) leads its name to decay into a pointer. (some resources get this wrong!)
Array names decay to pointers for pass-by-value
This means:
void foo(int* ptr);
int ar[10]; // an array
foo(ar); // automatically passing ptr to first element of ar (i.e. &ar[0])
There's also the hugely misleading "syntactic sugar" that looks like you can pass an array of arbitrary length by value:
void foo(int ptr[]);
int ar[10]; // an array
foo(ar);
But, actually, you're still just passing a pointer (to the first element of ar). foo is the same as it was above!
Whilst we're at it, the following function also doesn't really have the signature that it seems to. Look what happens when we try to call this function without defining it:
void foo(int ar[5]);
int main() {
int ar[5];
foo(ar);
}
// error: undefined reference to `func(int*)'
So foo takes int* in fact, not int[5]!
(Live demo.)
But you can work-around it!
You can hack around this by wrapping the array in a struct or class, because the default copy operator will copy the array:
struct Array_by_val
{
int my_array[10];
};
void func (Array_by_val x) {}
int main() {
Array_by_val x;
func(x);
}
This is somewhat confusing behaviour.
Or, better, a generic pass-by-reference approach
In C++, with some template magic, we can make a function both re-usable and able to receive an array:
template <typename T, size_t N>
void foo(const T (&myArray)[N]) {
// `myArray` is the original array of N Ts
}
But we still can't pass one by value. Something to remember.
The future...
And since C++11 is just over the horizon, and C++0x support is coming along nicely in the mainstream toolchains, you can use the lovely std::array inherited from Boost! I'll leave researching that as an exercise to the reader.
So I see answers explaining, "Why doesn't the compiler allow me to do this?" Rather than "What caused the standard to specify this behavior?" The answer lies in the history of C. This is taken from "The Development of the C Language" (source) by Dennis Ritchie.
In the proto-C languages, memory was divided into "cells" each containing a word. These could be dereferenced using the eventual unary * operator -- yes, these were essentially typeless languages like some of today's toy languages like Brainf_ck. Syntactic sugar allowed one to pretend a pointer was an array:
a[5]; // equivalent to *(a + 5)
Then, automatic allocation was added:
auto a[10]; // allocate 10 cells, assign pointer to a
// note that we are still typeless
a += 1; // remember that a is a pointer
At some point, the auto storage specifier behavior became default -- you may also be wondering what the point of the auto keyword was anyway, this is it. Pointers and arrays were left to behave in somewhat quirky ways as a result of these incremental changes. Perhaps the types would behave more alike if the language were designed from a bird's-eye view. As it stands, this is just one more C / C++ gotcha.
Arrays are in a sense second-class types, something that C++ inherited from C.
Quoting 6.3.2.1p3 in the C99 standard:
Except when it is the operand of the sizeof operator or the unary
& operator, or is a string literal used to initialize an array, an
expression that has type "array of type" is converted to an
expression with type "pointer to type" that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
The same paragraph in the C11 standard is essentially the same, with the addition of the new _Alignof operator. (Both links are to drafts which are very close to the official standards. (UPDATE: That was actually an error in the N1570 draft, corrected in the released C11 standard. _Alignof can't be applied to an expression, only to a parenthesized type name, so C11 has only the same 3 exceptions that C99 and C90 did. (But I digress.)))
I don't have the corresponding C++ citation handy, but I believe it's quite similar.
So if arr is an array object, and you call a function func(arr), then func will receive a pointer to the first element of arr.
So far, this is more or less "it works that way because it's defined that way", but there are historical and technical reasons for it.
Permitting array parameters wouldn't allow for much flexibility (without further changes to the language), since, for example, char[5] and char[6] are distinct types. Even passing arrays by reference doesn't help with that (unless there's some C++ feature I'm missing, always a possibility). Passing pointers gives you tremendous flexibility (perhaps too much!). The pointer can point to the first element of an array of any size -- but you have to roll your own mechanism to tell the function how big the array is.
Designing a language so that arrays of different lengths are somewhat compatible while still being distinct is actually quite tricky. In Ada, for example, the equivalents of char[5] and char[6] are the same type, but different subtypes. More dynamic languages make the length part of an array object's value, not of its type. C still pretty much muddles along with explicit pointers and lengths, or pointers and terminators. C++ inherited all that baggage from C. It mostly punted on the whole array thing and introduced vectors, so there wasn't as much need to make arrays first-class types.
TL;DR: This is C++, you should be using vectors anyway! (Well, sometimes.)
Arrays are not passed by value because arrays are essentially continuous blocks of memmory. If you had an array you wanted to pass by value, you could declare it within a structure and then access it through the structure.
This itself has implications on performance because it means you will lock up more space on the stack. Passing a pointer is faster because the envelope of data to be copied onto the stack is far less.
I believe that the reason why C++ did this was, when it was created, that it might have taken up too many resources to send the whole array rather than the address in memory. That is just my thoughts on the matter and an assumption.
It's because of a technical reason. Arguments are passed on the stack; an array can have a huge size, megabytes and more. Copying that data to the stack on every call will not only be slower, but it will exhaust the stack pretty quickly.
You can overcome that limitation by putting an array into a struct (or using Boost::Array):
struct Array
{
int data[512*1024];
int& operator[](int i) { return data[i]; }
};
void foo(Array byValueArray) { .......... }
Try to make nested calls of that function and see how many stack overflows you'll get!