Pass a function to another function with a pointer and a name

I am learning function pointers and this example from the wiki:

int add(int first, int second) { return first + second; } int subtract(int first, int second) { return first - second; } int operation(int first, int second, int (*functocall)(int, int)) { return (*functocall)(first, second); } int main() { int a, b; int (*plus)(int, int) = add; a = operation(7, 5, plus); b = operation(20, a, subtract); cout << "a = " << a << " and b = " << b << endl; return 0; } 

As I can see, plus is a pointer to the add function, and it goes to the function operation. It is clear. But what about subtract .

Why is the pointer not used for this? What is the difference between the two methods? Is this c++ specific?

+4
source share
2 answers

In C ++, a function can be automatically converted to a function pointer, so the following equivalents:

 b = operation(20, a, subtract); b = operation(20, a, &subtract); 

Since &substract is of the correct type ( int (*)(int, int) ), the code compiles and works as expected.

Is this C ++ specific?

I can not answer this, as it may be other languages. I am more than sure that there is.

+7
source

Why is a pointer not used for substract ?

In fact, the entire function name is a pointer in the corresponding scope. Here, in your code, when you define the substract() , add() function.

You also defined two variables named substract and add , the type of which is a pointer to a function: int (*)(int, int) . therefore, you can declare a new plus function pointer and assign add to it. All three variables are pointers.

Below is the assembly code generated by clang++ , which can give you a detailed explanation. I deleted all the inappropriate code. The function name is a little ugly to read, it is related to C ++ name mangling , you can just ignore the main characters and numbers to understand the name.

add() function:

  .text .globl _Z3addii .align 16, 0x90 .type _Z3addii,@function _Z3addii: # @_Z3addii .cfi_startproc # BB#0: # %entry movl %edi, -4(%rsp) movl %esi, -8(%rsp) movl -4(%rsp), %esi addl -8(%rsp), %esi movl %esi, %eax ret .Ltmp6: .size _Z3addii, .Ltmp6-_Z3addii .cfi_endproc 

substract function:

  .globl _Z8subtractii .align 16, 0x90 .type _Z8subtractii,@function _Z8subtractii: # @_Z8subtractii .cfi_startproc # BB#0: # %entry movl %edi, -4(%rsp) movl %esi, -8(%rsp) movl -4(%rsp), %esi subl -8(%rsp), %esi movl %esi, %eax ret .Ltmp7: .size _Z8subtractii, .Ltmp7-_Z8subtractii .cfi_endproc 

The label _Z3addii and _Z8subtractii gives the starting point of the two functions, which is also the address that points to the beginning of the function.

I added a few comments to the code to show how a function pointer that starts with ### works.

main function:

  .globl main .align 16, 0x90 .type main,@function main: # @main .cfi_startproc # BB#0: # %entry pushq %rbp .Ltmp16: .cfi_def_cfa_offset 16 .Ltmp17: .cfi_offset %rbp, -16 movq %rsp, %rbp .Ltmp18: .cfi_def_cfa_register %rbp subq $32, %rsp movl $7, %edi movl $5, %esi leaq _Z3addii, %rax ### Here, the assembly just load the label of _Z3addii, not a plus related variable, so in fact they are the same type. movl $0, -4(%rbp) movq %rax, -24(%rbp) movq -24(%rbp), %rdx ### move the value of the function pointer to the rdx register. callq _Z9operationiiPFiiiE movl $20, %edi leaq _Z8subtractii, %rdx ### Here, just load the label -f _Z8subsractii, which is the value of the function pointer substract. move it directly to rdx register. movl %eax, -8(%rbp) movl -8(%rbp), %esi callq _Z9operationiiPFiiiE leaq _ZSt4cout, %rdi leaq .L.str, %rsi movl %eax, -12(%rbp) callq _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc movl -8(%rbp), %esi movq %rax, %rdi callq _ZNSolsEi leaq .L.str1, %rsi movq %rax, %rdi callq _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc movl -12(%rbp), %esi movq %rax, %rdi callq _ZNSolsEi leaq _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %rsi movq %rax, %rdi callq _ZNSolsEPFRSoS_E movl $0, %ecx movq %rax, -32(%rbp) # 8-byte Spill movl %ecx, %eax addq $32, %rsp popq %rbp ret .Ltmp19: .size main, .Ltmp19-main .cfi_endproc 

In the above main function, we saw that the entire value of the function pointer has been moved to the rdx register. Here in the following functional function:

operation() function:

  .globl _Z9operationiiPFiiiE .align 16, 0x90 .type _Z9operationiiPFiiiE,@function _Z9operationiiPFiiiE: # @_Z9operationiiPFiiiE .cfi_startproc # BB#0: # %entry pushq %rbp .Ltmp10: .cfi_def_cfa_offset 16 .Ltmp11: .cfi_offset %rbp, -16 movq %rsp, %rbp .Ltmp12: .cfi_def_cfa_register %rbp subq $16, %rsp movl %edi, -4(%rbp) movl %esi, -8(%rbp) movq %rdx, -16(%rbp) movq -16(%rbp), %rdx movl -4(%rbp), %edi movl -8(%rbp), %esi callq *%rdx ### directly jump to the address, which is the value of the rdx register. addq $16, %rsp popq %rbp ret .Ltmp13: .size _Z9operationiiPFiiiE, .Ltmp13-_Z9operationiiPFiiiE .cfi_endproc 

So, from the assembly it is clear that the variable substract , add , plus in your given code is all pointers and taken from the label of the starting point of the function.

What is the difference between the two methods?

Since plus , add and substract are the same type function pointers, as Lucian Grigore says, they are the same.

From the assembler code above, we can also find out that both methods are exactly the same method call without any differences.

Is this pointed to by C++ ?

C family languages

and some other derived languages, such as obj-c .

Java language

In Java, there is such a thing as function pointers, but a class that implemnts interface could achieve the same purpose as a function pointer.

For example: you can first define an interface:

 interface StringFunction { int function(String param); } 

and then define a function that can accept objects that implement the interface:

 public void takingMethod(StringFunction sf) { //stuff int output = sf.function(input); // more stuff } 

And then you can define different classes that implements interface StringFunction , and use it as parameter takingMethod()

Python

In Python, a function name is just a variable type, and you can use it directly, for example, in the following ways:

 def plus_1(x): return x + 1 def minus_1(x): return x - 1 func_map = {'+' : plus_1, '-' : minus_1} func_map['+'](3) # returns plus_1(3) ==> 4 func_map['-'](3) # returns minus_1(3) ==> 2 

ruby

Ruby also has several ways: Function pointer in Ruby?

+3
source

Source: https://habr.com/ru/post/1484778/


All Articles