What does the compiler do when we define a function? And is the function name a pointer? Or maybe it's something else.
I wish I knew something about function names.
What does a function name stand for in C
The function name stands for the function.
What does the compiler do when we define a function?
The compiler remembers the name of the function, and it generates code to implement the function. It also remembers information from the declaration of the function, such as the return type and the types of the parameters, if a prototype form was used.
And is the function name a pointer? Or maybe it's something else.
The name of a function designates a function.
When a function name is used in an expression, it is automatically converted to a pointer to the function, with a couple of exceptions discussed below. Furthermore, effectively the only use for a function name is as a pointer to the function. Because of this, a programmer might think of the function name as a pointer, but it is not actually a pointer.
One exception to the automatic conversion is when a function name is used with sizeof. However, using sizeof on a function is usually an error (it is not defined by the C standard and can work only if a C implementation defines it as an extension), so this exception is never used in ordinary practice. The other exception is when a function name is used with unary &, as in &sin. In this case, we are explicitly taking the address of the function, which produces a pointer to the function, so there is no need for automatic conversion to a pointer to the function.
When you call a function, as with sin(x), the “function-call operator,” ( … ), takes a pointer to the function as its first operand. So, due to the automatic conversion, sin(x) is effectively (&sin)(x), which says to call the function whose address is &sin and pass it the argument x.
The fact that the function-call operator takes a pointer to a function is why we can use pointers for functions, as in double (*p)(double) = sin; printf("sin(.5) = %g.\n", p(.5));.
Related
Going over some code (written in the C language) I have stumbled upon the following:
//we have a parameter
uint8_t num_8 = 4;
//we have a function
void doSomething(uint32_t num_32) {....}
//we call the function and passing the parameter
doSomething(num_8);
I have trouble understanding if this a correct function calling or not. Is this a casting or just a bug?
In general, I know that in the C / C++ languages only a copy of the variable is passed into the function, however, I am not sure what is actually happening. Does the compiler allocates 32 bits on the stack (for the passed parameter), zeros all the bits and just after copies the parameter?
Could anyone point me to the resource explaining the mechanics behind the passing of parameter?
As the function declaration includes a parameter type list, the compiler knows the type of the expected parameter. It can then implicitely cast the actual parameter to the expected type. In fact the compiler processes the function call as if it was:
doSomething((uint32_t) num_8);
Old progammers that once used the (not so) good K&R C can remember that pre-ansi C only had identifier lists and the type of parameters was not explicitely declared. In those day, we had to explicitely cast the parameters, and when we forgot, we had no compile time warnings but errors at execution time.
The way the cast and the call is precisely translated in assembly language or machine instruction is just an implementation detail. What matters is that everything must happen as if the compiler had declared a temporary uint32_t variable had coerced the uint8_t value into the temporary and had passed the temporary to the function. But optimizing compilers often use a register to pass a single integer parameter. Depending on the processor, it could zero the accumulator, load the single byte in the low bits and call the function.
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.
GCC typically yields this warning when the proper header file is not included. This link --> www.network-theory.co.uk/docs/gccintro/gccintro_19.html says that because the function declaration is implicit (rather than explicitly declared via a header) the wrong argument types could actually be passed to the function, yielding incorrect results. I don't understand this. Does this mean the compiler generates code that pushes something, of the machine's word size, onto the stack for the callee to consume, and hopes for the best?
Detail is appreciated.
If the compiler doesn't have specific information about how the argument should be passed, such as when there's no prototype or for arguments that are passed where the prototype have an ellipsis ('...'), the compiler follows certain rules for passing the arguments. These rule basically follow what occurred in pre-standard (or K&R) C - before prototypes were used. Paraphrased from C99 6.5.2.2/6 "Function calls":
* the integer promotions are applied
* if the argument has float type it's promoted to double
After these default argument promotions are applied, the argument is simply copied to wherever the compiler normally copies arguments (generally, the stack). So a struct argument would be copied to the stack.
If the actual function implementation doesn't match how the compiler creates the parameters, then you get undefined behavior (with exceptions for signed/unsigned mismatch if the value can be represented or pointers to char and pointers to void can be mixed/matched).
Also in C90, if the function is implicitly declared (which C99 doesn't permit, though it does permit functions without prototypes), the return value is defaulted as int. Once again, the the actual function returns something else, undefined behavior results.
In classic K&R C, that's pretty much what happened; there were default coercions (anything smaller than (int) was promoted to (int), for example), and for backwards compatibility any function without a prototype is still called that way, but by and large the only indication you got for passing the wrong type was a weird result or maybe a core dump. Which is where you get in trouble, as when the function has a prototype the exact (not coerced/promoted) value is pushed. So if you're passing a (char), if there's a prototype in scope then a single byte is pushed by the caller, otherwise 4 bytes (on most current platforms). If the caller and callee disagree about this, Bad Things happen.
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.