Is it possible to pass a function pointer as a const argument?
I get the following gcc error:
warning: type defaults to 'int' in declaration of 'f'
[-Wimplicit-int] void execute(void (const *f)(void));
...when compiling this code:
#include <stdio.h>
void print(void);
void execute(void (const *f)(void));
int main(void)
{
execute(print); // sends address of print
return 0;
}
void print(void)
{
printf("const!");
}
void execute(void (const *f)(void)) // receive address of print
{
f();
}
This is not a duplicate of What is meaning of a pointer to a constant function?, which addresses pointers to const functions as opposed to a const function argument.
The syntax you want is:
void execute(void (* const f)(void));
This says that f is a const pointer to a function that takes no arguments ((void) is a special syntax for no arguments) and returns nothing (void). A const on the right side of an * says that the pointer is const. A const on the left side says the pointer points to something that is const.
The fact that it is a const pointer means that you will not change f (assign a new value) in the function, and the compiler should give you an error if you do (unless the change is hidden from it, which it can be by casts). It does not say anything about the function itself—the function pointed to is not const in any sense because the parameter is const.
When you wrote:
void execute(void (const * f)(void));
the const on the left side of the * means that the pointer was pointing to something that was const, rather than that the pointer itself was const. Since it was saying the pointer was pointing to something there and you did not list a specific type, the compiler warned you that the type was missing (and defaulted to int).
The const keyword should be placed between the pointer symbol (*) and the argument name (here, f):
void execute(void (* const f)(void))
{
f();
}
Now if you try to change f's value:
void execute(void (* const f)(void))
{
f = print;
f();
}
...your compiler should output an error similar to this one, as expected:
Error: cannot assign to variable 'f' with const-qualified type
Related
I would be very thankful if you could explain me what the following means:
void bar(char *a, char *b, unsigned short c) // (2)
{
...
}
void (*foo(void))(char *, char *, unsigned short) // (1)
{
return bar;
}
In particular,
Why there are no variable names in (1)?
What does void (*foo(void)) mean? How can *foo(void) be a name?
What does return bar mean? Returns it the address of the bar source code, or the result from bar, or else?
Is there any feature in making these signatures so complicated?
Could you give an example of the usage?
foo is a function that takes no arguments and returns a pointer to a function that takes three arguments of types char *, char * and unsigned short and returns void.
These declarations can be quite confusing because they should be read inside-out, bouncing left and right as needed:
foo is a thing ...
foo(void) ... apparently a function
*foo(void) ... whose return value can be dereferenced
(*foo(void))(...) ... and then called with these arguments
void (*foo(void))(...) ... which results in a value of type void.
You can also use cdecl.org to parse complex declarations for you:
declare foo as function (void) returning pointer to function (pointer to char, pointer to char, unsigned short) returning void
Usage examples:
// Immediately call the returned function.
// The similarity to the declaration is no coincidence!
(*foo())("hello", "world", 42);
// Store the returned function pointer for later invocation.
// This time there are no parentheses following the name, because
// this is a variable, not a function.
void (*fnPtr)(char *, char *, unsigned short) = foo();
(*fnPtr)("hello", "world", 42);
Argument names can always be omitted if the arguments aren't used inside the function. In this case, there isn't even a function body to use them in, because the body of foo isn't what the arguments are being passed to.
Following code works fine, however I was wondering if this is valid use of rule that void* is compatible with any other pointer
#include <stdio.h>
typedef struct {
int foo;
} SomeStruct_t;
typedef void(*SomeFunction_t)(void* ptr);
void bar(SomeStruct_t* str) {
printf("%d\n", str->foo);
}
void teddy(void* anyPtr) {
SomeStruct_t* str = (SomeStruct_t*)anyPtr;
printf("%d\n", str->foo);
}
int main()
{
SomeFunction_t functPtr = (SomeFunction_t)bar;
SomeStruct_t data = {.foo = 33};
functPtr(&data);
functPtr = teddy;
functPtr(&data);
return 0;
}
Question is, should I use bar or teddy variant? I prefer bar but I'm not sure if for some corner cases this might lead to hard to detect problem.
This is not valid:
SomeFunction_t functPtr = (SomeFunction_t)bar;
Because you're casing a function pointer of type void (*)(SomeStruct_t*) to type void (*)(void*) and subsequently calling it though the casted type. The function pointer types are not compatible because the parameters are not compatible. This triggers undefined behavior.
While a SomeStruct_t * can be converted to a void *, that conversion can't happen because the casted function pointer prevents it. There's no guarantee that SomeStruct_t * and void * have the same representation.
Using the function teddy which matches the function pointer type is safe. Also, you don't need to cast the parameter to SomeStruct_t * inside the function because conversions to/from void * don't require one in most cases.
I'm programming in C and I want to pass an array to a function; this function cannot modify the elements of the array. What is the correct syntax for the arguments of the function?
void func(const Foo array_in[])
or
void func(Foo const array_in[])
or maybe they are the same?
Thank you.
You should use pointer to constant in order to handle that:
#include<stdio.h>
void fun(const int *ptr)//pointer to constant - array boils down to pointer when passed to function
{
ptr[0]=9; //ERROR: Read-Only
}
int main(void)
{
int arr[]={1,2,3,4};
fun(arr);
return 0;
}
NOTE: Do not confuse it with constant pointer
First, the declarations const Foo array_in[] and Foo const array_in[] are exactly the same in C.
Second, when the parameter type of a function has "array of T" type, it is automatically adjusted to "pointer to T" type. So the compiler pretends as if you wrote:
void func(const Foo *array_in)
or equivalently
void func(Foo const *array_in)
Note that both const Foo *array_in and Foo const *array_in mean the exact same thing in C (pointer to const Foo). However, Foo * const array_in means something different (const pointer to Foo).
I want to acquire address of a needed function in function Check_Commands, put it in pointer fptr, and then call it. But, when trying to compile this code, I get following message:
"Error[Pe137]: expression must be a modifiable lvalue"
am I missing something?
void main(void)
{
...
void(*fptr)(CmdDataType);
Check_Commands(&fptr);
(*fptr)(&CmdData);
}
void Check_Commands(void (**ptrfuncptr)(CmdDataType))
{
...
**ptrfuncptr=&DispFirmware;
...
}
void DispFirmware(CmdDataType *CmdData_ptr)
{
...
}
This:
**ptrfuncptr=&DispFirmware;
should just be
*ptrfuncptr = DispFirmware;
Also there's no need to dereference a function pointer when calling, the name of a function can be thought of as a pointer to it so an ordinary call works just like that through a pointer.
There were a couple issues with your code. Here's the fixed version:
void main(void)
{
CmdDataType CmdData;
void (*fptr)(CmdDataType *);
Check_Commands(&fptr);
(*fptr)(&CmdData);
}
void Check_Commands(void (**ptrfuncptr)(CmdDataType *))
{
*ptrfuncptr=&DispFirmware;
}
void DispFirmware(CmdDataType *CmdData_ptr) { }
fptr is a pointer to a function which takes a CmdDataType pointer as a parameter, so that needed to be fixed.
And in the function Check_Commands the function pointer needs to be dereferenced only once.
I am observing error "warning C4090: 'function' : different 'const' qualifiers " because of below line of code. Going through other similar questions on SO I understand (not 100 percent) it is because of
--> const char* EmployeeList[] and my declaration in qsort of EmployeeList
#define Elements(array) (sizeof(array)/sizeof((array)[0]))
const char *EmployeeList[] =
{
"Larry Page", "Sergy Brin", "Sundar Pichai", "Merrisa Mayer"
};
// called from main
SortEmployee(EmployeeList, Elements(EmployeeList));
int Compare(const void *elemA, const void *elemB)
{
...
}
void SortEmployee(const char *EmployeeList[], size_t EmployeeCount)
{
qsort(EmployeeList, EmployeeCount, sizeof(EmployeeList[0]), Compare);
}
However I am unable to resolve it- Any pointers how to do it for array of strings.
The problem is qsort does not declare its argument as const, while your code does. That means qsort may (in theory) change data, pointed by EmployeeList. So, the compiler reports this error.
Here is the official example: https://msdn.microsoft.com/en-us/library/k77bkb8d.aspx
How ever, here is a simple version to demonstrate my idea:
void foo(char* a) {
*a = '1'; // I got pointer to char, and changed this char!
}
int main() {
const char *a = "A"; // I have "CONSTANT POINTER": it points to CONSTANT memory, that CAN NOT be changed (by the way, string constants can't in many environments).
foo(a); // I pass it to my function, that will change it.
return 0;
}
Image your compiler stores a in read-only memory (It can, because we told it "this is a pointer to READ ONLY data"). You then modify it (in main function). Something bad may happen. So, the compiler warns you "hey, you pass a pointer to constant data to some function, that does not know that this data is constant and may change it"