Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Let's say one wanted to create an array that could hold multiple function pointers & of different types.. how would he go about doing so ? Perhaps an array of void pointers could work ?... Well as it turns out, no since in order to use the functions stored in the void pointers you'd have to convert/cast them (the void pointers) back to function pointers and...
"A conversion between a function pointer and a void pointer is not possible. void* was never a generic pointer type for function pointers, only for object pointers. They are not compatible types.
[...] you can cast between void* and a function pointer, but what will happen is undefined behavior. You will be relying on system-specific non-standard extensions."
-#Lundin (here)
Instead...
Slightly better would be to use a function pointer type such as void (*)(void) as the generic pointer. You can convert to/from different function pointers, what will happen is compiler-specific (implementation-defined behavior). That is, the code will still be non-portable, but at least you don't risk a program crash from invoking undefined behavior.
-#Lundin (here)
That said, what does it even mean to convert from one function pointer to another ?
Could someone explain it. With an example perhaps.
It means that if you have two different function pointer types, such as for example:
int (*i)(int);
void (*v)(void);
Then you can make a conversion from one type to the other by using an explicit cast:
v = (void(*)(void))i;
This is allowed, but calling v() won't work. The standard says this, C17 6.3.2.3 §8:
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 referenced type, the behavior is undefined.
So if you try to call the function by v(); then it is likely undefined behavior. You can however convert back to the original type int(*)(int) without losing information.
This allows you to use a specific function pointer type as a "generic type". Rather than using void*, which isn't ok, as discussed here.
Notably, all code with function pointers get much easier to read if you use typedefs:
typedef int int_func (int);
typedef void void_func (void);
int main()
{
int_func* i;
void_func* v;
v = (void_func*) i;
i = (int_func*) v;
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I can pass arguments to a function in C in the following manner without any warnings or errors using gcc on ubuntu-64bit:
void func(char* test){
// do something here
}
void main() {
func((char*) "smaps");
}
I did not find a lot of examples about passing anonymous parameters to functions in C apart from one comment on a similar question about C++. I am thinking of using this technique (a lot) in my code which would be compiled on multiple AMD64/ARM devices as they become available (with mostly debian-based OSes). My question is, is this compiler-specific?
Output of gcc --version:
$ gcc --version
gcc (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406
UPDATE: Even though I think 4386427's was good enough for me, I would explain a bit more about the question as it was put on hold. I have a script which makes several calls to a specific function which takes in a char** as argument. I was of the view that I would need to explicitly declare a char** separately and pass it to the function by name every time I made a call to the function. I thought it would be more convenient to declare a string and pass it to the function at the same time; something like:
func( (char**) {"first_string", "second_string"} ).
My initial concern was is this allowed in C generally or is this a compiler-specific feature? 4386427's answer suggests that it is not compiler-specific, however I should be careful that the char** passed to the function would be immutable.
All parameters in C are passed by value. No information about the original object from which the value came is passed to the called function. In this sense, all C arguments are anonymous; no information about the identifier used in the calling function is passed.
In func((char*) "smaps");, the string literal "smaps" is converted to a pointer to char. Only the value of the pointer is passed to func. This is standard C.
(If you do want to pass information about an object to a function, you must do that manually. For example, you can take the address of an object and pass the resulting pointer to the function. Or you can pass the number of elements in an array to a function, along with the address of the first element.)
(In C, string literals such as "smaps" are automatically converted to a pointer to their first character, so you do not need to manually convert them with a char * cast. [This automatic conversion does not occur when the string literal is the operand of sizeof, _Alignof, or & or when it is used to initialize an array.])
It depends on what you are doing in the function. As long as you don't try to modify what test is pointing to, there is no problem. To indicate that it can't be changed, it is good to add const.
Like this the code is fine:
#include <stdio.h>
void func(const char* test){
printf("%s\n", test);
}
int main(void) {
func("smaps1");
func("smaps2");
func("smaps3");
func("smaps4");
return 0;
}
But if you try to change the value like:
void func(char* test){
test[0] = 'A';
printf("%s\n", test);
}
you have undefined behavior because modifying a string literal is undefined behavior.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I need to write a lib wrapper. My wrapper function prototype looks like this
int my_wrapper(char * configstr);
The function to be wrapped looks like this.
void my_function(char config[CONFIGSTRSIZE]);
I tried to do the following:
int my_wrapper(char * configstr)
{
my_function(configstr);
return 0;
}
This compiles and works but I receive an error. Telling my that the argument is a invalid type.
discards qualifiers from pointer target type
Is there a way to perform a cast to telling the compiler that the pointer of the calling function always is a pointer of the proper size?
It's more or less impossible to change the interfaces. I thank you for your feedback.
Is there a way to perform a cast to telling the compiler that the
pointer of the calling function always is a pointer of the proper
size?
It is not possible in C. Pointers do not have information about the size. You need to pass it as the additional parameter or have this information in the dereferenced object (for example first is the size, or termination value like C strings)
First of all, the following function declaration doesn't make much sense, although legal:
void my_function(char config[CONFIGSTRSIZE]);
It creates the wrong impression that you can somehow pass an array (with a fixed size). You can't in C. What actually happens is that C adjusts any array type in a function declaration to a corresponding pointer type, so this declaration ends up to be just
void my_function(char *config);
You could write it like this to emphasize that the pointer passed should point to an array (I prefer not to, but that's a matter of style):
void my_function(char config[]);
Now for your problem, according to the error message you get, you're probably trying to pass a const-qualified pointer here. Depending on what my_function() is doing, there are two solutions:
my_function() only reads the array. Then you should change the function prototype like this:
void my_function(const char *config);
my_function() also modifies the array. Then you can't pass some const data there, but you might take a copy of your data. Assuming the data is a string, one way to do it would be the following:
// having some const char *config
char *cfgcopy = malloc(strlen(config)+1);
if (cfgcopy) { // allocation succeeded
strcpy(cfgcopy, config);
my_function(cfgcopy);
// do something with the modified cfgcopy
free(cfgcopy);
}
Instead of malloc()/strcpy(), many implementations provide a "shorthand" strdup() function you could use. But be aware strdup() isn't part of standard C.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Is the following code in C correct? I am not 100% sure about the scope of function parameter "a":
void method(int a)
{
MyStruct mystruct;
mystruct.value = (void*) (&a);
nested_method_call(mystruct);
}
Let's assume it's:
void method(int a)
{
MyStruct x;
struct.value = (void*) a;
nested_method_call(x);
}
since struct cannot be used as a variable name.
a's scope is the function, so it is alive during nested_method_call, however, that is absolutely irrelevant because your nested_method_call isn't referring to it -- it's using a copy of a reinterpreted as void*. (Such reintepretation makes the code quite unportable and unusual, by the way. It might be a mistake.)
Edit:
void method(int a)
{
MyStruct mystruct;
struct.value = (void*) &a;
nested_method_call(mystruct);
}
is valid (though it's usually a good idea to pass structs by pointer because it's faster for any but very small structs). &a is a valid reference until the } of method.
You also shouldn't need that cast. If .value is void*, you don't need it. If it isn't, the cast makes &a convertible to any other data pointer, which is potentially a dangerous hole in the type system.
First of all, struct is a keyword in C and cannot be used as a variable name, so this is wrong code.
After that, casting an integer to pointer (and vice-versa) is implementation defined behaviour. You should better use uintptr_t for better, if you have to get that conversion done.
That said, from the basic premises of your question, the logic behind the code seems legit, there's no problem with the scope. In case you meant to ask about the lifetime ["The lifetime of an object is the portion of program execution during which storage is
guaranteed to be reserved for it"], then, it is until the end of the method() function and you're using it inside that limit, so you're good to go.
Corrected code: struct.value = (void*)&a;. Also some other validation needs to be done.
So, if you fully correct your code so that it complies properly then Correct word would be Lifetime instead of Scope. Lifetime of a will be till the end of function method. Therefore, a can still be accessed inside nested_method_call via pointer struct.value assuming type of struct.value is int*.
Learning and messing up with function pointers, I noticed a way to initialize void function pointers and cast them. Yet, although I don‘t receive any warning or error, either with GCC or VS’s compiler, I wanted to know whether it was dangerous or a bad practice to do this as I don't see this way of initializing function pointers often on the Internet. Moreover, do we call this generic function pointer?
#include <stdio.h>
#include <stdint.h>
#include <conio.h>
#define PAUSE (_getch())
uint16_t add(const uint16_t x, const uint16_t y) {
return x + y;
}
char chr(uint8_t test) {
return (char)test;
}
int main(void) {
void(*test)() = (void*)add;
const uint16_t x = 1, y = 1;
uint16_t value = ((uint16_t(*)())test)(x, y);
test = (void*)chr;
printf("%d\n", add(x, y)); // 2
printf("%d\n", value); // 2
printf("%c\n", ((char(*)())test)(100)); // d
PAUSE;
return 0;
}
Is this a generic function pointer
No, if I'm not terribly mistaken, there's no such thing as a "generic function pointer" in C.
and is it dangerous?
Yes, it is. It is evil.
There are a couple of things you need to know. First, unless you are running a system that conforms to POSIX,
void(*test)() = (void*)add;
is wrong. void * is a pointer-to-object type, and as such, it is not compatible with function pointers. (At least not in standard C -- as I mentioned, POSIX requires it to be compatible with function pointers too.)
The second thing is that void (*fp)() and void (*fp)(void) are different. The former declaration permits fp to take any number of parameters of any type, and the number of arguments and their types will be inferred when the compiler sees the first call to the function (pointer).
Another important aspect is that function pointers are guaranteed to be convertible across each other (AFAIK this manifests in them having the same representation and alignment requirements). This means that any function pointer can be assigned to (the address of) any function (after an appropriate cast), so long as you do not call a function through a pointer to an incompatible type. The behavior is well-defined if and only if you cast the pointer back to the original type before calling it.
So, if you want a "generic" function pointer, you can just write something like
typedef void (*fn_ptr)(void);
and then you could assign any pointer to function to an object of type fn_ptr. What you have to pay attention to is, again, the conversion to the right type when invoking the function, as in:
int add(int a, int b);
fn_ptr fp = (fn_ptr)add; // legal
fp(); // WRONG!
int x = ((int (*)(int, int))fp)(1, 2); // good
There are two serious problems here:
A cast from a function pointer to an object pointer (such as void *) triggers undefined behavior: in principle, it could crash your system (though in practice there are many systems where it will work fine). Instead of void *, it's better to use a function-pointer type for this purpose.
You're tricking the compiler into unknowingly passing an int to a function expecting a uint8_t. That's also undefined behavior, and it's very dangerous. Since the compiler doesn't know that it's doing this, it can't even take the most basic necessary steps to avoid smashing the stack — you're really gambling here. Similarly, this is a bit more subtle, but you're also tricking the compiler into passing two int-s into a function expecting two uint16_t-s.
And two lesser problems:
The notation for function pointer types on their own — e.g., in a cast — is confusing. I think it's better to use a typedef: typedef void (*any_func_ptr)(); any_func_ptr foo = (any_func_ptr)(bar).
It's undefined behavior to call a function pointer with a different signature than the actual function has. You can avoid that with careful coding — more careful than your current code — but it's tricky and risky.
You may corrupt the call stack with this, depending on the calling convention, specifically who's doing the cleanup: http://en.wikipedia.org/wiki/X86_calling_conventions With the callee cleanup, the compiler has no way of knowing how many variables you have passed on the stack at the point of cleanup, so passing the wrong number of parameters or parameters of the wrong size will end corrupting the call stack.
On x64, everyone uses the caller cleanup, so you're safe in this regard. The parameter values, however, will in general be a mess. In your example, on x64, they will be whatever was in the corresponding registers at the time.
C11 §6.3.2.3 (8) says:
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 referenced type, the behavior is undefined.
And §6.7.6.3 (15) says about compatible types of functions:
[…] 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. […]
So, if you had add and chr to take int arguments (an int has at least a width of 16 bit) that would be OK (if you didn't cast the function pointer to void *), but, as it is, it is UB.
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