我试图将函数指针调用为uint64_t值,并传递其地址存储在uint64_t结构中的参数。 这是代码。
double sum(double *a, long len){
double tmp = 0;
for(size_t i=0;i<len;i++){
tmp += a[i];
}
return tmp;
}
int main(){
long size = 1000;
double *a = new double[size];
for(int i=0;i<size;i++){
a[i] = i*1.0;
}
struct __attribute__ ((aligned(16))) args_t {
double *a_func;
long len_func;
} args;
args.a_func = a;
args.len_func = size;
double ret;
uint64_t arg_ptr = reinterpret_cast<uint64_t>(&args);
uint64_t arg_size = sizeof(args);
uint64_t func_ptr = reinterpret_cast<uint64_t>(&sum);
uint64_t func_ret = reinterpret_cast<uint64_t>(&ret);
// How should I call the function with arguments passed to it and get a return value?
}
Moto:我正在尝试构建一个库,它接受任何函数指针,它的参数和返回地址,它执行函数并通过返回地址返回值。 谢谢! :)
答案 0 :(得分:1)
试试这个。您在结构中缺少函数指针声明。
此外,您的func_ptr和func_ret调用未正确输入。我不会在uint64_t中保存指针类型,我建议使用void *
,因为它将是您的架构的正确长度。你绝对不应该在uint64_t中保存一个函数指针,因为标准不能保证sizeof(funcptr) == sizeof(void *)
。
double sum( double * a, long len )
{
//...
return 0.0;
}
int main(int argc, char const *argv[])
{
long size = 1000;
double * a = new double[size];
struct args_t
{
/** you need a ptr declaration */
double (*func_hsa)(double *, long );
double * a_hsa;
long len_hsa;
} args;
args.func_hsa = sum;
args.a_hsa = a;
args.len_hsa = size;
double ret;
ret = args.func_hsa(args.a_hsa, args.len_hsa);
return 0;
}
答案 1 :(得分:1)
Moto:我正在尝试构建一个库,它接受任何函数指针,它的参数和返回地址,它执行函数并通过返回地址返回值。
您需要至少在运行时动态地知道被调用函数的signature。
由于各种application binary interface(ABI)约定规定了不同且不兼容的calling conventions(例如,double
参数在浮点寄存器中传递,但int
值在某个整数寄存器中传递,这是处理器和ABI特定的,然后是编译器和链接器等...),你应该使用一个特定的库(它包含一些处理器和ABI特定的汇编代码)。 libffi就是这样一个库,您应该使用它。如果您无法使用它,请研究您的实施的ABI,例如: {/ 3}}适用于Linux / x86-64 ABI。
我试图将函数指针调用为uint64_t值,并传递其地址存储在uint64_t结构中的参数。
你不能以可移植的方式(不使用像this ...这样的东西)(即你需要一些处理器和ABI特定的代码,可能是汇编程序)。您隐含地假设参数是在某个堆栈上传递的,或者至少是通过可寻址的内存传递的,这通常是错误的,并且对于大多数libffi系统来说是错误的:大多数参数通常在x86-64中传递(和详细信息是处理器和ABI特定的,因此在Windows和Linux上都有所不同。)
问题不是函数指针,它是调用约定和传递的参数(以及结果传递)。
BTW,在C和C ++中,可转换为指针的整数类型为intptr_t
(来自C中的<stdint.h>
,来自C ++中的<cstdint>
;在ARM和&amp ;;等32位体系结构上使用(和来自/来自的函数指针)int64_t
。 x86不合适。
正如我评论的那样,如果您至少可以使用processor registers,C++11(即closures)和lambda functions非常有帮助。读
也是关于std::function
。
另见callbacks的GCC内置。
答案 2 :(得分:0)
所以, 最后我开始工作了。
double sum(double *a, long len){
double tmp = 0;
for(size_t i=0;i<len;i++){
tmp += a[i];
}
return tmp;
}
int main(){
long size = 1000;
double *a = new double[size];
for(int i=0;i<size;i++){
a[i] = i*1.0;
}
struct __attribute__ ((aligned(16))) args_t {
double *a_func;
long len_func;
} args;
args.a_func = a;
args.len_func = size;
double ret;
uint64_t arg_ptr = reinterpret_cast<uint64_t>(&args);
uint64_t arg_size = sizeof(args);
uint64_t func_ptr = reinterpret_cast<uint64_t>(&sum);
uint64_t func_ret = reinterpret_cast<uint64_t>(&ret);
// We are trying to make a generic function caller
size_t num_args = arg_size/8; // as elements of struct are 64bit long
uint64_t *varg = reinterpret_cast<uint64_t*>(arg_ptr);
switch(num_args){
case 2:
{
void* (*fun)(void*, void*) = reinterpret_cast<void* (*)(void*, void*)>(func_ptr);
uint64_t *ret_add = reinterpret_cast<uint64_t*>(func_ret);
*ret_add = reinterpret_cast<uint64_t>(fun((void*)varg[0], (void*)varg[1]));
break;
}
default:
break;
}
}
使用switch case不是一种正确的方法,但没有更好的方法来构建展开而不使用任何包或使用最新标准。虽然C ++ 14具有将元组作为参数列表传递的功能,但它并未完全实现。切换案例可以扩展为多个参数。