Home > OS >  Why is f(25) equal to pf(25)?
Why is f(25) equal to pf(25)?

Time:08-08

int f(int);
int (*pf)(int)=&f;
int ans;
ans=f(25);
ans=(*pf)(25);
ans=pf(25);

The book called Pointers on C says that f(25) is equal to pf(25) because when we call a function, the function name f is converted to a function pointer which points to the function's location in memory, and then executes the function code by calling the function with the function call operator. This contradicts what I originally thought.

When I declare int a and use a as an r-value, a itself identifies a memory location and we can get the value stored in the memory via a. So when I declare a function, why doesn't the function identify the memory location of the function but is instead converted to a pointer? And if I don't declare a pointer which points to the function, where is the pointer converted by function name stored?

The value of a is different from &a. When we want to get the value of a through &a we should use *. So why is f(25) is equal to pf(25)?

CodePudding user response:

On one level, this is just the way C is, and I cannot tell you why it is that way because I was not in the room when these design decisions were made.

I can try to offer some kind of explanation, though. Obviously, if you know the name of a function and you want to call it, you should be able to do that with no special ceremony:

double four = sqrt(16);

Now, if you have a pointer to a function, in the days before the C standard you had to dereference the pointer before you could call it:

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *))
{
  // ...
  comparison = (*compar)(a, b);
  // ...
}

The C committee thought you should be allowed to write that the same way as a normal function call,

comparison = compar(a, b);

But in order to do that without breaking any existing code (with the dereference) they had to make the rules that confuse you.

Thing is, unless you are writing a C compiler yourself, you can pretty much forget those rules exist. All you need to remember, in order to use the language effectively, is:

  1. Function call parentheses can be applied to either the name of a function, or to a variable, structure field, etc. holding a pointer to a function.
  2. If you use the name of a function, without function call parentheses, as an expression, you get a pointer to that function.
  3. The unary & operator does nothing when applied to the name of a function: sqrt == &sqrt. This is a special case for the names of functions; with compar declared as above, compar != &compar.
  4. The unary * operator does nothing when applied to a pointer to a function.

Hope that helps.

CodePudding user response:

So when I declare a function, why doesn't the function identify the memory location of the function but is instead converted to a pointer?

The compiler knows what things are and processes them according to the rules of C. If you use some a that is an int in an expression where its value is needed, the compiler generates code to get its value from memory.1 If you use some function f in an expression where it is not the operand of unary &, the compiler generates code to get its address.

And if I don't declare a pointer which points to the function, where is the pointer converted by function name stored?

The assembler, linker, and program-loading software work together to keep track of necessary addresses and make them available to the program. Typically, for addresses of functions, the compiler and assembler generate incomplete instructions with fields to be filled in, and the linker or program loader fill them in with information about where the functions are.

Footnote

1 Subject to modification by optimization.

CodePudding user response:

f, your function, is an address in memory. For example:

(gdb) x f
0x555555555125 <f>:     0xe5894855

This make int (*pf)(int) = &f a simple assignment and you can also write it as simple int (*pf)(int) = f:

(gdb) x pf
0x555555555125 <f>:     0xe5894855

The 3 ans= statements is simply different syntax for writing the same thing --- the same function call which you express with () per 6.5.2.2:

A postfix expression followed by parentheses () containing a possibly empty, comma-separated list of expressions is a function call. The postfix expression denotes the called function.
...
If the expression that denotes the called function has type pointer to function returning an object type, the function call expression has the same type as that object type, and has the value determined as specified in 6.8.6.4. Otherwise, the function call has type void.

  • Related