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().
Related
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;
}
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);
void foo(const char *s);
is equivalent to:
void foo(const char s[]);
Are there similar equivalents to the following two?
void foo(char * const s);
void foo(const char * const s);
In C++, the compiler will automatically convert function parameters of type array of N elements of type T (where N can be unknown) into pointer to T. In the same transformation top level const qualifiers for the arguments are dropped:
void f( const int x ); // => declares: void f( int )
void f( int * const ); // => declares: void f( int* )
That means that in the pointer case, the top level const qualifier is removed, and in the case of the array it is converted to pointer to. Now, on the other hand you cannot mix both, only because you cannot declare a constant array of N elements of type T, since arrays are always const. That means that you cannot write:
void f( const int a[] const ); // Invalid type definition
As the type of the parameter is invalid. If it was a valid type, then the conversions would apply, but because it is not, the compiler will reject the code before trying to perform the conversion.
This is treated in §8.3.5/3 of the C++03 standard (and probably somewhere close in C++11)
A single name can be used for several different functions in a single scope; this is function overloading (clause 13). All declarations for a function with a given parameter list shall agree exactly both in the type of the value returned and in the number and type of parameters; the presence or absence of the ellipsis is considered part of the function type. The type of a function is determined using the following rules. The type of each parameter is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively. After producing the list of parameter types, several transformations take place upon these types to determine the function type. Any cv-qualifier modifying a parameter type is deleted. [Example: the type void(*)(const int) becomes void(*)(int) —end example] Such cv-qualifiers affect only the definition of the parameter within the body of the function; they do not affect the function type. If a storage-class-specifier modifies a parameter type, the specifier is deleted. [Example: register char* becomes char* —end example] Such storage-class-specifiers affect only the definition of the parameter within the body of the function; they do not affect the function type. The resulting list of transformed parameter types is the function’s parameter type list.
Note that since the compiler will perform that conversion, it is better to write the actual type that is going to be used by the compiler, following the principle of least surprise:
void f( int a[10] ) { a[5] = 7; }
The compiler is not going to check that the passed array has 10 elements, it reads the declaration as void f( int * ), and will gladly accept a call with an array of less elements or even no array at all (a pointer to a single int). Using a pointer in the actual code:
void f( int *a ) { a[5] = 7; }
Will likely trigger some alarms in a code review: are we guaranteed that in all calls to f the argument will be at least 6 elements big? Should we not pass also the size just in case?
You cannot in C89, but in C99 you can declare the equivalents as:
void foo(char s[const]);
void foo(const char s[const]);
this will be useful in some cases:
class AA {
void foo(char a[]);
void foo(const char a[]);
};
void AA::foo(char* const a) { … }
void AA::foo(const char* const a) { … }
and in C:
extern void foo(char a[]);
extern void fooc(const char a[]);
void foo(char* const a) { … }
void fooc(const char* const a) { … }
I thought that a pointer can be null, while an array argument cannot be null (and that the compiler is permitted to optimize knowing that; however on a simple example gcc-4.6 don't do such an optimization, even with -O3).
I am expecting that the compiler would optimize differently the two functions below. It does not. I don't have my C standard at hand to check if it could remove the test in ss below.
int s (int *t)
{
if (!t)
return 0;
return t[0] + t[1];
}
int ss (int t[])
{
if (!t) // never false, since t is an array!!
return 0;
return t[0] + t[1];
}
I am trying to understand the rules of c++ automatic and explicit conversions in regular or member function calls. I wrote the following code and it fails compilation:
#include <iostream>
#include <string>
using namespace std;
class testExplicit {
public:
int intval;
short shortval;
double doubleval;
char charval;
string strval;
testExplicit(int a1, short a2, double a3, char a4, string& a5):
intval(a1),shortval(a2),doubleval(a3),charval(a4),strval(a5){}
void getVal(int& a) { a = intval; cout << "IntVal\n"; }
// void getVal(short& a) { a = shortval; cout << "Short Val\n"; }
// void getVal(double& a) { a = doubleval; cout << "Double Val\n"; }
// void getVal(char& a) { a = charval; cout << "Char Val\n"; }
// void getVal(string& a) { a = strval; cout << "String Val\n"; }
};
int main( int argc, char **argv ) {
string s ("test Str");
testExplicit test (100,10,10.05,5,s);
int i;
char c;
double d;
short f;
test.getVal(i);
test.getVal(c);
test.getVal(d);
test.getVal(f);
return 0;
}
However, can I conclude that the functions only expect the exact matching parameter? I remember reading that automatic conversions happen according to the conversion rules. Can some shed some light on the correct rules pls?
Here is the error:
test.cpp: In function 'int main(int, char**)':
test.cpp:38: error: no matching function for call to 'testExplicit::getVal(char&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
test.cpp:39: error: no matching function for call to 'testExplicit::getVal(double&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
test.cpp:40: error: no matching function for call to 'testExplicit::getVal(short int&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
Thanks
void getVal(int& a);
This function takes an int by reference. You must pass it an int. This is similar to how if you had a function
void getVal(int* a);
you would need to pass it a pointer to an int (not a pointer to a short or any other type).
One reason for this is that you are able to modify the int from within the function. In order to allow you to pass an object of another type (e.g. a short) to this function, a temporary object of type short would have to be created at runtime and a reference to that temporary object would have to be passed.
This wouldn't be ideal because you might accidentally end up passing the wrong type of object (e.g. a short) and expecting it to be modified by the function, when in fact a temporary copy of type int would be modified by the function, not the original short.
You are, however, permitted to bind const references to temporary objects, so if your function was declared as
void getVal(const int& a);
you would be able to pass it any type that is convertible to int. This makes some sense, since the function cannot modify the referenced object (because it is a const reference), so the "oops, I'm accidentally modifying a temporary object" problem doesn't exist.
Conversions can also take place when you pass by value, but this too makes sense: when you pass by value, a copy has to be made anyway (the copy that is passed to the function by value), so the conversion can take place as part of that copy.
The problem is that if an implicit conversion is required, then a temporary variable is created. You cannot have a non-const reference to a temporary variable, so you would need to make your member function void getVal(const int &a) or void getVal(int a).
Implicit conversion should be avoided. C++ is a strongly typed language it is far better to create functions for the types you wish to accept, use templates, or explicitly cast your type to another type, etc.
Constructor casting or using static_cast<>, dynamic_cast<>, or reinterpret_cast<> are some of the options depending on the situation when you need to convert types from one to another.
Templates can allow you to handle multiple types a little easier.
template<typename T>
void getVal(const T& a)
{
// do something
}
Implicit conversions are done by creating an rvalue (temporary), and rvalues cannot be bound to non-const references. That is the reason why it is not working. If, on the other hand you change the signature to take the arguments either by value or by constant reference, then it will work:
void f( int a ) { std::cout << a << std::endl; }
void g( const int& b ) { std::cout << b << std::endl; }
int main() {
char c = 'a'; // note that this the ASCII value of 'a'
f( c );
g( c );
short s = 4;
f( s );
g( s );
}
Pass by reference means, creating an alias for the same type. So try changing void getVal(int& a) to void getVal(int a), to work for the other function calls differing the passing parameter type