arrays - 如何按照以下代码示例将指针函数 abc(x, y) 存储到数组中?
问题描述
- 功能 1。
- 它是一个指针函数。
char *abc(unsigned int a, unsigned int b)
{
//do something here ...
}
- 功能二
- 将功能 1 转化为功能 2。
- 我正在尝试将 abc 函数存储到一个数组中,但是我得到的错误是:错误:赋值给具有数组类型的表达式。
fun2()
{
unsigned int x, y;
x= 5, y=6;
char *array1;
char array2;
for(i=0; i<3; i++)
{
array2[i] = abc(x, y);
}
}
解决方案
您不能将函数的调用存储在 C 中,因为它会破坏许多现有的涉及寄存器参数传递的流行优化 - 请参阅,因为通常参数在执行流程转移到调用站点之前立即分配其参数值 - 编译器可能会选择使用寄存器来存储这些值,但就目前而言,这些寄存器是易失性的,因此如果我们要延迟实际调用,它们将在稍后的时间被覆盖 - 甚至可能通过对某个函数的另一个调用,该函数也将其参数作为寄存器传递. 一个解决方案——我个人已经实现了——是让一个函数通过重新分配给适当的寄存器和任何进一步的参数来模拟你的调用——给堆栈。在这种情况下,您将参数值存储在平面内存中。但这必须专门为此目的在汇编中完成,并且特定于您的目标体系结构。另一方面,如果您的架构没有使用任何此类优化 - 它可能会更容易,但仍然需要手写汇编。
无论如何,这不是标准(甚至据我所知甚至是预标准)C 随时实现的功能。
例如,这是我前段时间写的 x86-64 的实现(用于 MSVC masm 汇编器):
PUBLIC makeuniquecall
.data
makeuniquecall_jmp_table dq zero_zero, one_zero, two_zero, three_zero ; ordinary
makeuniquecall_jmp_table_one dq zero_one, one_one, two_one, three_one ; single precision
makeuniquecall_jmp_table_two dq zero_two, one_two, two_two, three_two ; double precision
.code
makeuniquecall PROC
;rcx - function pointer
;rdx - raw argument data
;r8 - a byte array specifying each register parameter if it's float and the last qword is the size of the rest
push r12
push r13
push r14
mov r12, rcx
mov r13, rdx
mov r14, r8
; first store the stack vars
mov rax, [r14 + 4] ; retrieve size of stack
sub rsp, rax
mov rdi, rsp
xor rdx, rdx
mov r8, 8
div r8
mov rcx, rax
mov rsi, r13
;add rsi, 32
rep movs qword ptr [rdi], qword ptr [rsi]
xor r10,r10
cycle:
mov rax, r14
add rax, r10
movzx rax, byte ptr [rax]
test rax, rax
jnz jmp_one
lea rax, makeuniquecall_jmp_table
jmp qword ptr[rax + r10 * 8]
jmp_one:
cmp rax, 1
jnz jmp_two
lea rax, makeuniquecall_jmp_table_one
jmp qword ptr[rax + r10 * 8]
jmp_two:
lea rax, makeuniquecall_jmp_table_two
jmp qword ptr[rax + r10 * 8]
zero_zero::
mov rcx, qword ptr[r13+r10*8]
jmp continue
one_zero::
mov rdx, qword ptr[r13+r10*8]
jmp continue
two_zero::
mov r8, qword ptr[r13+r10*8]
jmp continue
three_zero::
mov r9, qword ptr[r13+r10*8]
jmp continue
zero_one::
movss xmm0, dword ptr[r13+r10*8]
jmp continue
one_one::
movss xmm1, dword ptr[r13+r10*8]
jmp continue
two_one::
movss xmm2, dword ptr[r13+r10*8]
jmp continue
three_one::
movss xmm3, dword ptr[r13+r10*8]
jmp continue
zero_two::
movsd xmm0, qword ptr[r13+r10*8]
jmp continue
one_two::
movsd xmm1, qword ptr[r13+r10*8]
jmp continue
two_two::
movsd xmm2, qword ptr[r13+r10*8]
jmp continue
three_two::
movsd xmm3, qword ptr[r13+r10*8]
continue:
inc r10
cmp r10, 4
jb cycle
mov r14, [r14 + 4] ; retrieve size of stack
call r12
add rsp, r14
pop r14
pop r13
pop r12
ret
makeuniquecall ENDP
END
您的代码将如下所示:
#include <stdio.h>
char* abc(unsigned int a, unsigned int b)
{
printf("a - %d, b - %d\n", a, b);
return "return abc str\n";
}
extern makeuniquecall();
main()
{
unsigned int x, y;
x = 5, y = 6;
#pragma pack(4)
struct {
struct { char maskargs[4]; unsigned long long szargs; } invok;
char *(*pfunc)();
unsigned long long args[2], shadow[2];
} array2[3];
#pragma pack(pop)
for (int i = 0; i < 3; i++)
{
memset(array2[i].invok.maskargs, 0, sizeof array2[i].invok.maskargs); // standard - no floats passed
array2[i].invok.szargs = 8 * 4; //consider shadow space
array2[i].pfunc = abc;
array2[i].args[0] = x;
array2[i].args[1] = y;
}
//now do the calls
for (int i = 0; i < 3; i++)
printf("%s\n", ((char *(*)())makeuniquecall)(array2[i].pfunc, array2[i].args, &array2[i].invok));
}
对于您的特定情况,您可能不需要它,您只需存储每个参数并直接调用函数即可逃脱 - 即(加上此方法不会特定于 x86-64):
//now do the calls
for (int i = 0; i < 3; i++)
printf("%s\n", array2[i].pfunc(array2[i].args[0], array2[i].args[1]));
但是我的实现使您可以灵活地为每个调用存储不同数量的参数。
请注意,请考虑本指南以在 msvc 上运行上述示例(因为它需要为汇编代码添加 asm 文件)。
我喜欢这样的菜鸟问题,因为它们让您思考为什么 xy 功能实际上并不存在于该语言中。
推荐阅读
- php - 为什么这个 php 程序的输出不正确
- reactjs - 滑块占用过多 RAM,导致内存泄漏
- phpmyadmin - 在 Xampp 中访问 phpMyAdmin 失败:设置无效
- flutter - 如何在 Flutter 中运行所有模块的所有测试
- c# - 如何在 C# 中设置 BsonDateTime 序列化程序默认选项
- ios - 在 Swift 5 中解码 JSON 后得到 nil
- mysql - MySQL 将多个参数绑定到单个查询
- r - 如何确保作者拥有唯一的姓名
- python - 程序跳过 if 语句
- python - 在python中以特定字符开头和结尾的字符串中查找并打印子字符串的索引