So I was wondering how they work. To explain what I mean by a "function caller" a good example of what I mean would be glutTimerFunc, it is able to take in a function as a parameter and call it even with it not knowing it is declared. How is it doing this?
What you're talking about is called a callback and is implemented with function pointers in C and C++.
Since you mentioned glut, let's take a real example directly from the freeglut source code. I'll use glutIdleFunc instead of glutTimerFunc because the code is simpler.
In glut, the idle function callback (what you supply to glutIdleFunc) is a pointer to a function that takes no parameters and returns nothing. A typedef is used to give such a function type a name:
typedef void (* FGCBIdle)( void );
Here, FGCBIdle (short for FreeGlut CallBack Idle) is defined as a pointer to a function that takes no parameters and whose return type is void. This is just a type definition that makes writing expression easier, it doesn't allocate any storage.
Freeglut has a structure called SFG_State that holds various settings. Part of the definition of that structure is:
struct tagSFG_State
{
/* stuff */
FGCBIdle IdleCallback; /* The global idle callback */
/* stuff */
};
The struct holds a variable of type FGCBIdle, which we established is another name for a specific function pointer. You can set the IdleCallback field to point to the address of a function that is supplied by the user using the glutIdleFunc function. The (simplified) definition of that function is:
void glutIdleFunc( void (* callback)( void ) )
{
fgState.IdleCallback = callback;
}
Here, fgState is a SFG_State variable. As you can see, the glutIdleFunc takes one parameter which is a function pointer to a function that takes no parameters and returns nothing, this parameter's name is callback. Inside the function, the IdleCallback inside the global fgState variable is set to the user supplied callback. When you call the glutIdleFunc function, you pass the name of your own function (e.g. glutIdleFunc(myIdle)), but what you're really passing is the address of the function.
Later, inside the big glut event processing loop initiated by glutMainLoop, you'll find this code:
if( fgState.IdleCallback )
{
/* stuff */
fgState.IdleCallback( );
}
If a user supplied idle callback is available, it is called in the loop. If you check the function pointer tutorial at the beginning of my post you will understand the syntax better, but I hope the general concept makes more sense now.
The parameter is a pointer to a function. It is the caller's responsibility to ensure that the function declaration matches the requirements (e.g., number and type of parameters, calling convention).
A function passed as a paramter is passed as a function pointer.
In compiled code, a function is nothing more than an address which the CPU can vector off to to execute. When you are passing a function pointer, the compiler (and later the linker) insert the correct address into the call.
Function parameters must match exactly as the executing code will simply push values on the stack (or registers, depending on the architecture) and expect to pop off (read out) the return value.
Related
I've been reading through the Riot Vanguard (kernel level anti-cheat driver) source code and have some difficulties understanding what I think is a function call.
((void(*)())(RtlFindExportedRoutineByName(VgkDriverObject->DriverStart, "Egg")))();
RtlFindExportedRoutineByName is a function which returns a PVOID, and what I currently have thought up is: take this function which returns a PVOID, cast it to a pointer to a function which returns nothing and call it.
Would love some insight from someone who is more knowledgeable.
EDIT: Why is this better than just calling the function as it is defined?
RtlFindExportedRoutineByName is a function which returns a PVOID, and what I currently have thought up is: take this function which returns a PVOID, cast it to a pointer to a function which returns nothing and call it.
That is correct.
Why is this better than just calling the function as it is defined?
In order to call a function via a pointer, the pointer must be a function pointer. You cannot call a PVOID (which is a typedef for void *) directly, without casting it beforehand.
The function RtlFindExportedRoutineByName is probably returning a pointer to a function that the program does not have direct access to. Therefore, it can only call it via a function pointer.
Hey I have implemented some callbacks in my C program.
typedef void (*server_end_callback_t)(void *callbackArg);
then I have variable inside structure to store this callback
server->server_end_callback = on_sever_end;
What I have noticed it that I can pass in on_server_end callback function implementation that skips void *callbackArg and the code works correctly (no errors).
Is it correct to skip some arguments like void * implementing callback functions which prototypes takes such arguments?
void on_server_end(void) {
// some code goes here
}
I believe it is an undefined behavior from the C point of view, but it works because of the calling convention you are using.
For example, AMD64 ABI states that the first six arguments get passed to the calling function using CPU registers, not stack. So neither caller nor callee need no clean-up for the first six arguments and it works fine.
For more info please refer the Wikipedia.
The code works correctly because of the convention of passing arguments. Caller knows that callee expects some arguments - exactly one. So, it prepares the argument(s) (either in register or on stack - depending on ABI on your platform). Then callee uses those parameters or not. After return from callee, caller cleans up the stack if necessary. That's the mistery.
However, you shall not abuse this specific behaviour by passing incompatible function. It is a good practice to always compile your code with options -W -Wall -Werror (clang/gcc and compatible). Enabling such option would provide you a compilation error.
C allows a certain amount of playing fast and loose with function arguments. So
void (*fptr) ();
means "a pointer to a function which takes zero or more arguments". However this is for backwards compatibility, it's not wise to use it in new C code. The other way round
void (*fptr)(void *ptr)
{
/* don't use the void */
}
/* in another scope */
(*fptr)(); /* call with no arguments */
also works, as long as you don't use the void *, and I believe it is guaranteed to work though I'm not completely sure about that (on a modern machine the calling convention is to pass the first arguments in registers, so you just get a garbage register, and it will work). Again, it is a very bad idea to rely on it.
You can pass a void *, which you then cast to a structure of appropriate type containing as many arguments as you wish. That is a good idea and a sensible use of C's flexibility.
Is it correct to skip some arguments like void * implementing callback functions which prototypes takes such arguments?
No it is not. Any function with a given function declaration is not compatile with a function of a different function declaration. This rule applies for pointers to functions too.
So if you have a function such as pthread_create(..., my_callback, ...); and it expects you to pass a function pointer of type void* (*) (void*), then you cannot pass a function pointer of a different format. This invokes undefined behavior and compilers may generate incorrect code.
That being said, function pointer compatibility is a common non-standard extension on many systems. If the calling convention of the system is specified in a way that the function format doesn't matter, and the specific compiler port supports it, then such code might work just fine.
Such code is however not portable and not standard. It is best to avoid it whenever possible.
I was recently reading about the usage of const keyword as function arguments in C and the way to use that has been mentioned in When and for what purposes should the const keyword be used in C for variables and been accepted as correct answer. In this post, one point mentions that
Never use const in a function prototype for a parameter passed by
value. It has no meaning and is hence just 'noise'.
I used this way and it works for me but I am not sure why that is a noise for parameters passed by value and yet not a noise for the parameters passed by reference (more aptly the pointer values in C as there is not concept of pass by value and pass by reference in C). So, by this explanation when I pass a pointer as a function argument and use a const keyword; I have to do this for both the declaration in the header file and the definition in the C file but I need not use the const keyword for a non-pointer argument in the declaration (header file) and only use it while defining the function in the C file.
Any explanations?
The statement you quote is a bit misleading, because in C, all arguments are passed by value.* I suppose it is trying to distinguish between the arguments themselves and, for the special case of arguments that are pointers, their referents.
In any event, the point is that const-qualifying a function parameter in the function declaration conveys no information whatever to callers. Regardless of such qualification, the function cannot modify the caller's copy of any argument anyway, because arguments are passed by value.
*Note, however, that arrays are never passed at all. In function call expressions, as in most contexts, array values "decay" to pointers, and those pointers are passed by value. This produces an effect similar, but not identical, to what you would have if arrays were passed by reference.
It's the rule. If in the declaration of a function, you don't mark your parameters const, you can mark them const in the definition.
Some folk like to mark as many parameters const as possible in the definition since it can guard against unintentional modification of the function parameters; which could introduce bugs. Personally I don't do this but plenty of houses (including a large bank headquartered in Scotland) insist on the style.
Posting this here because I wrote it for a code review and figured it was worth preserving:
Adding const to a value-type parameter in the function declaration is useless. The caller won't care whether the parameter is modified or not because the caller's data won't be affected in any way. The parameter is a separate object than the argument that was passed in, constructed by copy [or by move for rvalue arguments into move-constructible parameters (since C++11)].
Adding const to a value-type parameter in the function definition marks the separate, function-local object as const. This is essentially the same as marking a local variable 'const', and value-type parameters should usually be treated as local variables when determining whether the value-type should be const.
The C & C++ standards demand that compilers & linkers be smart enough to match the following declaration with its definition:
// Declaration
void Foo(int bar);
// Definition
void Foo(const int bar){
printf("%i", bar);
}
I know the reasons why this is a bad idea and I also know that this is the reason C++ templates were created, but I'm doing it in C for the fun and learning.
I'm embedding Python into my application and I wanted to make it possible to register certain C functions, with any arbitrary type, to be callable at the application run-time. Because of this a pointer to them is stored (as a simple void*).
With some basic macro fun I have gotten all the information I need about these functions and stored that too - the function pointer, the size of the return value (and if it is void), the number of arguments and each of their sizes.
So I'm stuck at the final stage - which is the actual calling of the function pointer with the appropriate data. I'm fairly certain this sort of thing should be possible (I've caused stack errors in my own time), but I was wondering if there was a more...legitimate way to do it.
I guess the ideal would look something like this:
void call_function(void* function, void* return, void* arg_data, int arg_data_size);
Does such a thing exists?
Thanks
You can declare a function pointer void* (*f) (void*); that points to a function that takes a void* argument and returns a void* return value -- you can put this in the first parameter of call_function.
Then call call_function as:
void* function(void*);
ret_type ret;
arg_type arg_data;
call_function(&function, (void*)&ret, (void*)&arg_data, sizeof(arg_data));
where arg_type is the actual argument type you want to use inside function and ret_type is the actual type of the return value of function.
Note: you might want to specify the size of the return value type as well.
Note: this will work with any function of one argument. The solution can be extended to a fixed/known number of arguments in function, but not to handle an unknown number of arguments.
Note: naming the second parameter return is not allowed as return is a keyword.
I am building a C-Interpreter (in C++) which builds an AST. I want to give the user the opportunity to communicate with real DLLs. For example: I call a function from a DLL. This function expects an pointer to an function (to callback). There is the problem: I don't have a real address to a function, because the function which I want to give to the DLL-function only exists as node in my AST. Is there a way to solve the problem? I thought about using a proxy-like function built-in into my interpreter, which delegates to the function in my AST. The problem is, that the proxy-function must have the same signature to be callable from the DLL-function ... and i can't create dynamic functions at runtime.
You don't say specifically which API/dll you're trying to use, but MOST of them provide for a void * (or LPVOID on windows) of 'user data' that is supplied along with the callback function pointer and will be passed to the callback function, along with whatever other arguments are appropriate for the callback.
What you can do is pass in a pointer to your AST as this extra pointer, and write a small wrapper function for the actual callback which converts this void * back into an AST * and then invokes your interpreter on that AST.