Why pointer is not used for substract
?
In fact, all the function name is a pointer in its corresponding live scope. Here, in your code, when you define the function substract()
, add()
.
You also defined two variable named substract
and add
, which type is function pointer: int (*)(int, int)
. so you can declare a new function pointer plus
, and assign add
to it. All the three variables is all pointer.
The following is the assembly code generated by clang++
, which could give you a detail explanation. I have removed all the un-relevant code. The function name is a bit ugly to read, this is because of the C++ name mangling, you can just ignore the capital chars and digits to easily understand the name.
function add()
:
.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
function substract
:
.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 _Z3addii
and _Z8subtractii
label give the start point of the two function, which also is an address that point to the start of the function.
I have add some comments in the code to show how the function pointer works, which started with ###
.
function main
:
.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 assebly, we saw that all the function pointer value is moved to the register rdx
. Here in the following operation function:
function operation()
:
.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, we can see from the assembly that, the variable substract
, add
, plus
in your given code are all pointers, and comes from the label of the start point of the function.
What is the difference between the two method?
Since the plus
, add
and substract
are all the same type function pointers, just like Luchian Grigore says, they are the same.
From the above assembly code, we can also find out that, the two method are absolutely the same method call, without any difference.
Is it C++
specified?
C
family languages
and some other derived languages, like obj-c
support function pointers directly.
Java language
In Java, there is such a concept named function pointers, but an class
which implemnts
an interface` could achieve the same goal as function pointer.
For example:
you could define an interface first:
interface StringFunction {
int function(String param);
}
and then define an function that could accept objects that implements the interface:
public void takingMethod(StringFunction sf) {
//stuff
int output = sf.function(input);
// more stuff
}
And then you could define different classes that implements
interface StringFunction
, and use it as an parameter of takingMethod()
Python
In Python, function name is just a type of variable, and you could directly use it, like 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 have some similar ways: Function pointer in Ruby?