This question already has answers here:
What does (void)var actually do?
(4 answers)
Closed 3 years ago.
I am reading this book and I have come across this code:
static void
task1(void *args) {
int i;
(void)args;
for (;;) {
gpio_toggle(GPIOC,GPIO13);
for (i = 0; i < 1000000; i++)
__asm__("nop");
}
}
I understand all (relatively) except for line 5. What is (void)args; doing?
args is not used in the function body, and I know that if an argument is not used then one could write
static void
task2(void *args __attribute((unused))) {
// code here
}
which is not being done here. So what is (void) written like that doing?
In general when one does not use an function argument, the compiler is likely to warn you about it. After all if you aren't going to use it why put it there in the first place?
In effect it is an artificial use of the argument that does nothing useful other than telling the compiler you know what you are doing, so "Shatupalready with the warning!"
(void) args works on all of the platforms that I have seen. I believe the __attribute((unused)) is a gcc specific thing.
Every expression has a type. Any expression can be turned into a statement by adding a semicolon. If an expression-statement yields a non-void value, that value is discarded.
Compilers will often warn about a value being discarded. Even a simple case like
printf("hello world\n");
quietly discards the int value returned by printf; a compiler warning might remind the programmer to test that value and take some action if it indicates that the call failed. (Most compilers will not warn in this particular case, since printf calls are usually used in a statement context, with the result ignored.)
Casting an expression to type void discards the result, but it does so explicitly. This is likely to silence a compiler warning.
As far as the language is concerned, a (void) cast converts a result to type void, which is equivalent to discarding that result. From a programmer's point of view, a (void) cast can silence a warning that a value is not used, since you're explicitly ignoring it and asserting to the compiler that you know what you're doing (even if you don't).
Quoting the C standard (N1570 draft), 6.3.2.2:
The (nonexistent) value of a void expression (an expression that has
type void) shall not be used in any way, and implicit or
explicit conversions (except to void) shall not be applied to
such an expression. If an expression of any other type is evaluated as
a void expression, its value or designator is discarded. (A void
expression is evaluated for its side effects.)
and 6.2.5 paragraph 19:
The void type comprises an empty set of values; it is an
incomplete object type that cannot be completed.
It's a compiler warning (-W unused-variable or -W all) they're suppressing by using it. You are correct in that __attribute__((unused)) is a valid C macro to do what you're asking, but it's a matter of preference. It's also not supported by all C compilers.
Sources:
http://www.keil.com/support/man/docs/armcc/armcc_chr1359124983230.htm
https://en.cppreference.com/w/cpp/compiler_support
void is an empty data type, it can be used in a different number of situations.
A function that "returns" void doesn't return anything (and by definition is a procedure, not a function).
A void* (pointer of void) is often used as a generic pointer (a pointer to a memory address with no particular data type associated with it). The compiler will let you assign this pointer to any other pointer type without need of explicit conversion.
malloc() for example, returns void* so you can do things like int* v = malloc(sizeof(int)*10)); without need of explicitly recasting the return value of malloc() to int*.
The other way around is also true, a function that takes void* as parameter will take any pointer type without need of explicit conversion.
Related
I have a function that returns a value. Is it safe to cast it to a function pointer type that returns nothing (void) and then call it? Does the C standard give enough guarantees to make this safe on any platform, and equivalent to calling the function normally while ignoring the return value?
Bonus question: Is there a standards compliant calling convention that is used in practice on some platform and with which this is not safe to do?
Example code:
#include <stdio.h>
// simple function with a a side-effect;
// it is useful to call even when ignoring the return value
int f(int x) {
return printf("%d\n", x);
}
typedef void (*fun_t)(int);
int main() {
fun_t g = &f; // cast to void return type, issues a warning
g(123); // <-- is this safe, and equivalent to calling f(123) instead?
return 0;
}
Notes:
This question is concerned only with changing the return type during the cast, not changing the types of any function parameters.
I know that this is safe on the x86 and x64 platforms I use, assuming the default calling convention, but I would like to know if it is safe in general.
I know that it is easy to work around this when necessary by writing a wrapper void fw(int x) { f(x); }. However, I would still like to know if doing this is safe so that I can better understand the fundamentals of the C language.
No. This call invokes Undefined Behavior. See https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p8
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.
At link https://port70.net/~nsz/c/c11/n1570.html#6.7.6.3p15 one can find rules of compatibility of function types:
For two function types to be compatible, both shall specify compatible return types. 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. ...
No.
In addition to tstanisl's answer:
Consider a big return value as for example this structure:
struct big_t {
long la[1000000];
};
It is allowed as a return type.
Some compilers, including GCC for x86/x64, provide the space for the return value at the caller's site and call the function with a pointer to this space. In your use case, this pointer is not set.
So it is not safe on x86 or x64, nor any other architecture.
Have a lot of fun debugging the crashes!
Is it safe to cast these 2 functions to callback pointer type then call them without casting back?
typedef void (*callback)(int i, ...);
void foo() {
// something.
}
void foo2(int i, int j) {
// something.
}
int main(void)
{
callback c = (callback)&foo, c2 = (callback)&foo2;
(*c)(0); (*c2)(0,1);
return 0;
}
The cast itself is safe, but you must use the correct type when calling the function. This is what the C standard 6.3.2.3 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.
In your case void (*)(int i, ...) isn't compatible with either of the other functions, so this code is wildly undefined behavior. However, some compilers provide non-standard extensions for generic function pointer use with the non-prototype void foo() style. But that one in turn is obsolete C and shouldn't be used for that reason - always use void foo (void) in C and never empty parenthesis.
Is it safe to cast these 2 functions to callback pointer type then call them without casting back?
No. The types of the two functions are not compatible with type callback, in the language specification's sense of "compatible", therefore calling either of those functions via a pointer of type callback invokes undefined behavior. Overall, non-variadic function types are never compatible with variadic ones, and in practice, many implementations use different calling conventions for one type than for the other, such that there is no plausible reason even to hope that calling a function of one variety as if it were of the other variety would have the desired effect in any consistent way.
You have several alternatives, among them:
Use different callback types for different purposes, each appropriate to its intended callback interface. This way you can avoid casting the callback functions at all. This would be my recommendation. It achieves the best type safety, and you need somehow to keep track of what the actual callback type is anyway, so that you can call it correctly.
Use a union of function pointer types. Callback specifiers assign to the appropriate member of the union, and callback callers select the appropriate member.
typedef union {
int (*unary)(int i);
int (*binary)(int i, int j);
} callback;
// ...
callback cb1 = { .unary = foo };
callback cb2 = { .binary = foo2 };
cb1.unary(1);
cb2.binary(1, 2);
You might even use a tagged union -- one that additionally carries information about which member is used. That would be a bit more complicated to use, but it would give you a means to achieve additional type safety. One of the variations on this approach would be my fallback recommendation if you need a single data type with which multiple callback types can be conveyed.
Choose a single callback type that meets all your needs. One way to do that would be to give it a parameter of type void *, by which callback functions can accept any number and type of inputs by, for example, a pointer to a suitable structure type.
typedef int (*callback)(void *);
struct one_int { int i1; };
struct two_int { int i1, i2; };
int foo(void *args) {
struct one_int *one_int = args; // ...
}
int foo2(void *args) {
struct two_int *two_int = args; // ...
}
Choose any function type as callback. Cast to that type going in, and back to the original type for calls.
Specify the callback type without a prototype. In C, if a function declaration that is not part of a definition of that function does not specify a parameter type list then that means that no information is provided about the parameters (unlike in C++, where that means that the function has no parameters). That is compatible with functions requiring any specific number of arguments -- but not variadic ones -- provided that applying the default argument promotions to the parameter types yields compatible types. Type int is a fine parameter type in that regard. The main ones that would be a problem are integer types narrower than int, plus float.
typedef int (*callback)();
This would allow exactly the usage you describe for the particular function types in your example.
callback cb1 = foo;
callback cb2 = foo2;
(*cb1)(1); // or just cb1(1)
(*cb2)(1, 2); // or just cb2(1, 2)
Contrary to another answer's claim, support for this approach does not constitute an extension to any version of the C language specification published to date. Supporting it is a requirement for conformance with any of C89, C99, C11, and C17. However, it has been declared "obsolescent" in C17, which constitutes a warning that it may be removed from some future version of the language specification. I expect that it indeed will be removed, possibly as soon as the next version of the specification, though obsolescence does not guarantee that.
No, the pointer will still point to the 'old' function (without parameters) and if you call the function, you will put variables on the stack which will never be used.
More problematic will be, if you have a pointer to the function with parameters and cast it to the function without parameters. Then, parameters will be fetched from the stack which you never put there. It is pure chance which values the program will operate on.
Note: This is the most likely behavior, but compilers are not bound to implement it this way (due to undefined behavior).
I guess you know this, but the safer way to do this sort of thing (although it's somewhat of a nuisance) is with explicit casts:
(*(void (*)(int, int))c2)(0, 1);
Here we:
take the generic "callback" function pointer c2
cast it to the correct function pointer type void (*)(int, int)
call it with the correct arguments
More problematic is your first callback, c. You're trying to call it with one integer argument 0, but you defined foo as accepting 0 arguments. So a more correct callback to foo as defined would be
(*(void (*)(void))c)();
Or if foo was supposed to take one argument of type int, that would be
(*(void (*)(int))c)(0);
And although as I said, the extra casts here can be a nuisance, this exercise illustrates their benefit: I didn't notice the mismatch between foo's definition and your callback c, until the compiler warned me about it after I inserted what I thought were the correct casts.
Without the casts, as other answers have explained, the code is unlikely to work. In particular, the attempt to make the callback type "variadic" (that is, with the ... in the prototype) does not help, and may very well hurt. These days, the calling conventions for variadic functions tend to be different from those for ordinary functions (a distinction which the ANSI/ISO C Standard has made since the beginning, although this marked a departure from K&R C). So if the compiler thinks that c2 points to a function of type void (*)(int, ...), and you call it with (0, 2), the compiler may very well use a different calling convention (the "varargs" one), and it might not be compatible with the non-varargs foo2, which is actually of type void (*)(int, int).
The bottom line is that it is safe to cast (convert) between function pointer types, but you must do it "on both ends"; that is, you must convert back to the correct type before calling. And "the correct type" must match both the actual function being called, and the actual arguments being passed.
If i declare any variable using void, it gives error but sizeof(void) is 1.
What is reason for this?
void var; // it gives error
printf("sizeof(void) = %d", sizeof(void)); //prints 1
sizeof (void) is not valid in C and is allowed in GNU C as an extension to allow pointer arithmetic with void *.
From gcc documentation:
In GNU C, addition and subtraction operations are supported on pointers to void and on pointers to functions. This is done by treating the size of a void or of a function as 1. [...] consequence of this is that sizeof is also allowed on void and on function types, and returns 1.
The void type, in several programming languages derived from C and Algol68, is the type for the result of a function that returns normally, but does not provide a result value to its caller. Usually such functions are called for their side effects, such as performing some task or writing to their output parameters.
Upto my knowledge, You cannot use void as datatype, as the value is true or false statement the Boolean value will be 1 by default, so, it prints 1.
c.f. Is there a specific reason why “void” was not simply defined as “typedef struct{} void” (i.e. an empty struct) with appropriate casting rules? ...
This was originally suggested by Steve Bourne in AB33/Mar 1972 for Algol68 ...
Note: Algol68 doesn't have pointer arithmetic... but array slicing is available.
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