- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
假设我想实现具有异步行为的函数,或者我只想使用函数指针,那么调用函数指针是否被授权导致调用关联函数,紧接着调用下一条指令?
例子
#include <iostream>
#include <cstdint>
int triple(int a) { return a * 3; }
void foo() { std::cout << "executing foo()" << '\n'; }
using fptrT = int (*)(int);
int main()
{
fptrT p = triple;
p(3);
foo();
}
p(3)
求值和
foo()
执行的时间有何解释?
最佳答案
Christope's answer是正确的。这是补充。
函数指针本身不能提供异步行为。标准实际上禁止这样做。我对C标准比C++标准要熟悉得多,所以我会使用它。我的理解是,在这一点上,两者都应该是大致相同的。
C11标准对函数和函数指针的描述
让我们从C中函数调用的定义开始,见6.5.2.2第3段:
postfix表达式后跟括号()是一个函数调用,该表达式可能包含一个空的、逗号分隔的表达式列表。postfix表达式表示被调用的函数。表达式列表指定函数的参数。
并由第1段中的约束修改:
表示被调用函数(92)的表达式应具有指向返回void或返回数组类型以外的完整对象类型的函数的类型指针。
重要的是,随附的脚注92指出:
通常,这是转换作为函数指示符的标识符的结果。
因此,C11标准基本上将函数调用定义为调用函数指针的东西。并且,为此目的,命名函数标识符将自动转换为指向标识符中代码的函数指针。因此,C看不到函数和函数指针之间的区别。
实验
虽然参考标准总是很好的,但是看看可靠的实现是如何工作的也是非常有用的。让我们做一个测试,在这里我们编写相当简单的代码,然后查看底层程序集
代码:
#include <stdio.h>
#include <stdlib.h>
typedef void (*my_func_ptr)(int,int);
void my_function(int x, int y)
{
printf("x = %d, y = %d, x + y = %d\n",x,y,x+y);
}
int main()
{
/* declared volatile so the compiler has to call the function through
* the pointer and cannot optimize it to call the function directly */
volatile my_func_ptr fp = my_function;
my_function(3,5);
fp(3,6);
return 0;
}
gcc
)来编译代码,这实际上是LLVM库的gcc前端。要查看程序集,我在
gcc -o fptr fptr.c
下运行程序,在
lldb
处设置断点,并发出
main
命令,该命令将反汇编当前函数。我将
disassemble -f
用于英特尔风格的程序集。
settings set target.x86-disassembly-flavor intel
中的默认值是a T&T样式,看起来有点不同。
lldb
例程如下:
push rbp
mov rbp, rsp
sub rsp, 0x20 ; sets up the stack frame
mov edi, 0x3 ; my_function(3,5). 1st arg: edi
mov esi, 0x5 ; 2nd arg: esi
lea rax, qword ptr [rip - 0x59] ; loads address of my_function into rax
mov dword ptr [rbp - 0x4], 0x0
mov qword ptr [rbp - 0x10], rax ; saves address of my_function on stack
call 0x100000ed0 ; explicit call to my_function
mov eax, 0x0
mov edi, 0x3 ; fp(3,6). 1st arg: edi
mov esi, 0x6 ; 2nd arg: esi
mov rcx, qword ptr [rbp - 0x10] ; rcx <- address of my_function from stack
mov dword ptr [rbp - 0x14], eax
call rcx ; call address at rcx
mov eax, dword ptr [rbp - 0x14]
add rsp, 0x20
pop rbp
ret
main
操作调用实际调用。唯一的区别是第一次硬编码地址,第二次将地址存储在
call
寄存器中。还要注意的是,代码没有异步性。
f();
g();
rcx
中未使用
f()
的任何副作用,反之亦然。编译器能够在函数中对此进行推理的唯一方法是,编译器是否可以使用函数的代码。通常,这对于函数指针是不可能的,因为指针可以指向满足函数指针类型约束的任何函数。
关于c++ - 函数指针在C和C++中都立即返回吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26918903/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!