I'm trying to understand the difference between the following two blocks of code:
void f(int (*func)(int))
{
func(5);
}
and
void g(int (func)(int))
{
func(5);
}
Both functions work in the same way given the following code:
int blah(int a)
{
cout << "hello" << endl;
return 0;
}
int main()
{
f(blah);
g(blah);
return 0;
}
However, if I write the following code:
int (*foo)(int);
int (goo)(int);
foo = blah;
goo = blah;
I get a compile error for goo = blah. But in the first example, I could call make the function call g(blah) which appears to be quite similar to goo = blah. Why does one work and not the other?
Somewhat confusingly, you can declare a function to take a function as a parameter (even though that makes no sense), and the effect is to make the parameter a function pointer. This is similar to the way you can declare a function parameter that looks like an array, but is actually a pointer.
The function argument can be the name of the function, with or without a & to explicitly take its address. If you omit the &, then there's an implicit function-to-pointer conversion. Again, this is similar to passing a (pointer to) an array, where the implicit array-to-pointer conversion means you only need to write the array's name, rather than &array[0].
That rule doesn't apply when declaring variables; int goo(int); (with or without unnecessary parentheses around goo) declares a function, not a pointer, and you can't assign to functions.
It's analogous to the difference between an array and a pointer, e.g. if you have:
char *foo;
char bar[N];
you can do:
foo = bar;
but you can't do:
bar = foo;
When the function type is used in an argument declaration, it's translated to the equivalent function pointer, just as declaring:
void fun(int arr[]);
is translated to:
void fun(int *arr);
Related
Functionally and syntactically speaking, is there a difference between a function whose prototype is int foo(void) and int foo(void *)?
I know the difference between, for example, int bar(int) and int bar(int *) - one of them is looking for an int, and the other is looking for an int pointer. Does void behave the same way?
From this answer on Software Engineering, void is treated specially depending on how it's used. In C and C++, void is used to indicate an absence of a data type, whereas void * is used to indicate a pointer which points to some data/space in memory that does not have a type. void * cannot be dereferenced on its own, and must be cast to another type first. This cast need not be explicit in C, but must be explicit in C++. (This is why we don't cast the return value of malloc, which is void *.)
When used with a function as a parameter, void means a total absence of any parameters, and is the only parameter allowed. Attempting to use void like a variable type or include other arguments results in a compiler error:
int foo(void, int); //trying to use "void" as a parameter
int bar(void baz); //trying to use "void" as an argument's type
main.c:1:8: error: 'void' must be the first and only parameter if specified
int foo(void, int);
^
main.c:2:14: error: argument may not have 'void' type
int bar(void baz);
^
It is similarly impossible to declare a variable with type void:
int main(void) {
void qux; //trying to create a variable with type void
}
main.c:5:8: error: variable has incomplete type 'void'
void qux;
void as a return value for a function indicates no data will be returned. Since it is impossible to declare a variable of type void, it is impossible to catch the return value of a void function, even with a void pointer.
void foo(int i) { return; }
int main(void) {
void *j;
j = foo(0);
return 0;
}
main.c:5:5: error: assigning to 'void *' from
incompatible type 'void'
j = foo(0);
^ ~~~~~~
The typeless void * is a different case. A void pointer indicates a pointer to a location in memory, but does not indicate the type of data at that pointer. (This is the used to achieve polymorphism in C, such as with the qsort() function.) These pointers can be tricky to use, however, as it is very easy to accidentally cast them to the wrong type. The code below won't throw any compiler errors in C, but results in undefined behavior:
#include <stdio.h>
int main(void) {
double foo = 47.2; //create a double
void *bar = &foo; //create a void pointer to that double
char *baz = bar; //create a char pointer from the void pointer, which
//is supposed to hold a double
fprintf(stdout, "%s\n", baz);
}
The following code, however, is perfectly legal; casting to and from a void pointer never changes the value it holds.
#include <stdio.h>
int main(void) {
double foo = 47.2;
void *bar = &foo;
double *baz = bar;
fprintf(stdout, "%f\n", *baz);
}
47.200000
As a function parameter, void * indicates that the type of the data at the pointer you are passing in is not known, and it is up to you, the programmer, to properly handle whatever is at that memory location. As a return value, void * indicates that the type of the data being returned is not known or is typeless, and must be handled by the program.
int quux(void *); //a function that receives a pointer to data whose type is not known, and returns an int.
void *quuz(int); //a function that receives an int, and returns a pointer to data whose type is not known.
tl;dr void in a function prototype means "no data" and indicates no return value or no parameters, void * in a function prototype means "the data at the pointer this function is given does not have a known type" and indicates a parameter or return value whose pointer must be cast to a different type before the data at the pointer can be used.
foo(void) - function with no parameters
foo(void *) - function with one void * parameter
What is void *? It is just the pointer to the data with no specified type. It Can be casted to any other pointer type
unsigned add(void *arr)
{
unsigned *uarr = arr;
return uarr[0] + uarr[1];
}
Functionally and syntactically speaking, is there a difference between a function whose prototype is int foo(void) and int foo(void *)?
There is a difference:
int foo(void) declares a function that accepts no arguments.
int foo(void *) declares a function that accepts single argument of type void*.
In C++, int foo(void) is equvalent to int foo().
I know void (*)(int) is to function pointer but what is void(int)?
It's used for std::function template.
Say I have a function void fun(int){} : decltype(&fun) gives void(*)(int) but decltype(fun) gives void(int)
If T is a type, then T* denotes the type "pointer-to-T".
The type void(int) is a function type, it's the type of a function taking one int and returning void. For example, it is the type of f if f is declared as void f(int);
If T = void(int), then T* is spelled void(*)(int), so the latter is the type of a function pointer. You can also form a reference to a function, which is T& = void(&)(int); this is occasionally more useful (e.g. you can take the address of a function lvalue).
Aside note: Function lvalues decay to their function pointer very easily. You can call a function either via a function lvalue or via a function pointer. When used as an operand for the indirection operator (*), the function value decays, so you can dereference the pointer again and again:
printf("Hello world\n"); // OK
(*printf)("Hello world\n"); // also OK
(****printf)("Hello world\n"); // four-star programmer
Some of the only times that a function does not decay is when used as the operand of the address-of operator, or when bound to a reference:
void f(int); // our example function
void(*p1)(int) = &f; // no decay of "f" here
void(*p2)(int) = f; // "f" decays
void(&r1)(int) = f; // no decay of "f" here
void g(void(&callback)(int), int n) {
callback(n);
}
g(f, 10); // no decay of "f" here
template <typename F, typename ...Args>
decltype(auto) h(F&& callback, Args&&... args) {
return std::forward<F>(callback)(std::forward<Args>(args)...);
}
h(f, 10); // no decay of "f" here
void (*whatever)(int)
should be read as: whatever is a pointer, pointing to a function, that accepts one int as argument, and returns nothing (ie., void).
void whatever(int)
should be read as: whatever is a function (NOT a pointer), that accepts one int as argument, and returns nothing (ie., void)
Once the pointer to a function is initialized to point to a valid function (one that satisfies the prototype), then you can invoke the function either through its "real" name, or through the pointer.
Pointers to functions are very useful - they're variables, just like anything else, so you can pass them around to other functions (see e.g. qsort()), you can put them in structs, etc..
Given this, the following code is valid:
#include <stdio.h>
void myfun(int x) {
printf("The value of X is %d\n", x);
}
int main() {
void (*myfunp)(int);
myfunp = &myfun;
myfun(13);
myfunp(12);
return 0;
}
void(*)(int) should be read as type of a pointer which is pointing to a function, that accepts one int as argument, and returns nothing.
For understanding more on function to pointer and its usage please check here: http://www.cprogramming.com/tutorial/function-pointers.html
I have a few functions that return void. I made pointers to these functions and wanted to have an array of these functions:
Why does this code work:
#include <cstdio>
using std::puts;
void tell() {
puts("hi");
};
void slap() {
puts("goodbye");
}
int main(int argc, char *argv[])
{
void (*tp)() = tell;
void (*sp)() = slap;
void(*funcs[])() = {tp, sp};
for (auto point:funcs) {
point();
}
return 0;
}
When I try this code with out specifying a pointer in funcs (i.e. void(funcs[])() = {tp, sp}; I get " error: 'funcs' declared as array of functions of type 'void ()' " Which is exactly what they are - so why is that an error?
I also don't get the syntax, wouldn't the () at the end of void(*funcs[])() indicate actually calling a function?
C++ Standard 8.3.5/10 says:
There shall be no arrays of functions, although there can be arrays of pointers to functions.
The declaration of "funcs" must be read using the "spiral rule":
funcs[]: funcs is an array
*funcs[]: funcs is an array of pointers
(*funcs[])(): funcs is an array of pointers to functions with no parameters
void (*funcs[])(): funcs is an array of pointers to functions with no parameters returning void.
Well you can declare it explicitly like this:
void (*actions[5])();
But this is nearly unreadable.
To make it more readable use a typedef.
typedef void(*Action)(); // Action is the typename for a pointer
// to a function return null and taking
// no parameters.
Action actions[5]; // An array of 5 Action objects.
Or for your purposes:
int main()
{
Action actions[] = {&tell, &slap};
}
Without the asterisk, void (funcs[])() declares an array of functions rather than array of pointers to functions. The latter is allowed in the C++ grammar while the former is not.
[dcl.array]/p1:
T is called the array element type; this type shall not be a reference type, the (possibly cv-qualified) type void, a function type or an abstract class type.
The contents of the initializer-list ({tp, sp}) are functions but they are converted to pointers via the function-to-pointer conversion:
[conv.func]/p1
An lvalue of function type T can be converted to a prvalue of type “pointer to T.” The result is a pointer to the function.
Note that C++ also doesn't allow an array of references.
I also don't get the syntax, wouldn't the () at the end of void(*funcs[])() indicate actually calling a function?
No, this is a declaration of an array type. The () is part of the construction of the type which specifies the argument list of the function. The entire type indicates "an array of pointers to functions which take zero arguments (()) and return void". It may become clearer with the use of a type alias:
using void_f = void (*)();
void_f funcs[] = {tp, sp};
use like this:
int main(int argc, char *argv[])
{
void (*tp)() = tell;
void (*sp)() = slap;
void (*funcs[])() = {tp, sp};
for (void (*point)():funcs)
{
point;
}
return 0;
}
When I'm passing function as parameter to other functions in c++ , do I have to specify it as
void callOtherFunctions(void f());
or
void callOtherFunctions(void (*f)());
I have no idea what happens under the hood , so I tried running both versions with a simple program as below , replacing the necessary part for 2nd run.
#include <iostream>
using namespace std;
void printHello();
void callOtherFunctions(void f());
int main() {
callOtherFunctions(printHello);
return 0;
}
void printHello(){
std::cout<<"\n Hello World";
}
void callOtherFunctions(void f()){
for (int i=0;i<5;++i){
f();
}
}
and to my surprise , both execute with same output and no warnings. So which is the preferred way , or correct way ( in case I'm doing something wrong ). And what actually happens in each case , when I pass pointer - does it executes address function there and when I pass function - does it copies down whole function there? or something else?
Here is Ideone Link
void callOtherFunctions(void f());
and
void callOtherFunctions(void (*f)());
are identical. Quoting N1570,
§6.7.6.3/8 A declaration of a parameter as "function returning type"
shall be adjusted to "pointer to function returning type", as in
6.3.2.1.
I would prefer the function pointer syntax because more people would be familiar with it and it's explicit what you mean. To answer your second question, a conversion also happens in certain cases (informally known as "decay"):
§6.3.2.1/4 A function designator is an expression that has function
type. Except when it is the operand of the sizeof operator, the
_Alignofoperator,65) or the unary & operator, a
function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type".
Function parameter declarations are somewhat unusual; the compiler will adjust some of the declared types. This is one of them: function parameters of function type are adjusted to the corresponding pointer type.
Other common adjustments to function parameters are array to pointer type, and removing top-level const:
int foo(int a[5]); // a is a pointer
int foo(const int a); // foo() can be called with a non-const int argument.
I have written the following code:
#include "stdafx.h"
#include <iostream>
using namespace std;
double funcA()
{
return 100.0;
}
int g(double (*pf)())
{
cout << (*pf)() << endl;
return 0;
}
int g2(double pf())
{
cout << pf() << endl;
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
g(&funcA); // case I
g(funcA); // case II
g2(funcA); // case III
g2(&funcA); // case IV
return 0;
}
I have run the above code on VS2008 and each function call returns '100'.
Here is the question:
Q1> Is there any problem in the code?
Q2> It seems that C++ doesn't make difference between *pf and pf. Is that correct?
Thank you
C++ does, in fact, make a distinction between the types double() and double(*)(), but the difference is subtle. When you pass a function type as an argument to a function, the function-type automatically "degrades" to a function pointer. (This is similar, I suppose, to how an array type degrades to a pointer type when passed as a function argument.)
However, a function type and a function-pointer type are still different types, according to the C++ type-system. Consider the following case:
void g() { }
template <class F>
struct Foo
{
Foo(const F& f) : func(f)
{ }
void operator()() { func(); }
F func;
};
int main ()
{
Foo<void()> f(g);
f();
}
This should fail to compile, since you cannot declare a function type as an automatic variable. (Remember, functions are not first-class objects in C++.) So the declaration F func; is invalid. However, if we change our main function to instead instantiate the template using a function pointer, like so:
int main ()
{
typedef void(*function_pointer)();
Foo<function_pointer> f(g);
f();
}
...now it compiles.
The following functions are identical:
int g(double (*pf)())
{
cout << (*pf)() << endl;
return 0;
}
int g2(double pf())
{
cout << pf() << endl;
return 0;
}
Dereferencing a function pointer (as shown in g) is the same as calling that function's name.
Q2> It seems that C++ doesn't make
difference between *pf and pf. Is that
correct?
There is a difference between *pf and pf (as variables). If pf is a function, *pf and pf() are identical (Note the parentheses).
With most modern compilers, there is no difference between "(*variable)." and "variable->". However, one must check the class in use to see if it overrides the dereference operator.
Many programmers use typedef when defining function pointers, primarily to make reading easier. Also, the double pf() syntax may be prone to readability errors and can get confused with executing a function on parameter line.
There's no problem or difference in the code you posted. However, if you are writing templates which take functors, you should use the syntax in g2. Consider the following:
template<typename Iter, typename Func>
void for_each(Iter begin, Iter end, Func functor)
{
for(; begin != end; ++begin)
{
functor(*begin);
}
}
Note that if you put the dereference operator before functor, you limit the utility of the algorithm you have written to function pointers. However, if you don't put that there, someone can pass an STL functor, such as something returned by std::bind2nd.
Therefore I would overall recommend using the second (without *) syntax where possible.
Consider the following piece of code
void pf();
void (&prf)() = pf; // OK, bind prf to pf
void (&prf)() = &pf; // ill-formed, can't bind prf to an function pointer value
On the other hand
void (*ppf)() = pf; // OK, function decays to a pointer
void (*ppf)() = &pf; // OK, pointer assigned to a pointer
So there is an implicit conversion from a function to a pointer (which is called "decay"). This also makes you able to say ***...***pf - arbitrarily many times dereference it - in each step a function to pointer conversion occurs which undoes the effect of the previous dereference.
In function parameter lists, a T f() and a T (*f)() are equivalent ways (except for spelling) of declaring a parameter
void f(void g()); // g has type void (*)()
void f(void (*g)()); // g has type void (*)()
A reference will inhibit this parameter type adjustment
void f(void (&g)()); // g has *not* the type void (*)()
This is exactly the same as for array declared parameters: Parameters are never arrays, but they will always be pointers, if they were declared as being arrays.