我需要写一些像double (*fun)(double)
这样的匿名管道,但是WriteFile(pipe, fun, 4, written_bytes, 0)
会导致管道接收器出错ReadFile(read_pipe, fun, 4, written_bytes, 0)
。有没有办法做到这一点?
我有个主意。我可以使用相同类型的字段创建结构:
struct Foo
{
double (*f)(double);
};
然后我写了WriteFile(hWritePipe_StdIN, &to_process, sizeof(Foo), &bytes, 0);
但我有问题,管道接收器永远不会结束读取数据:
ReadFile(hReadPipe, &to_process, sizeof(Foo), &bytes, 0);
答案 0 :(得分:2)
它有一些问题:
首先,你应该知道函数的大小。
如果您这样做,只需致电WriteFile(pipe, funcPtr, funcSize, ...)
即可将其转移。
其次,该功能应仅包含position-independent code,并且不会处理任何数据。 例如。像这样的功能不会起作用:
double fun(double x)
{
int arr[10000]; // implicit function call (alloca or something like this)
printf("some");
static int some = 1;
return globalVal + (++some);
}
因为函数printf
将具有不同的地址,并且在另一个进程中将没有静态变量和字符串
(好吧,也许您也可以传输数据,但是您无法生成PI代码。)
所以,有了这些限制,你可以发送一个函数:
__declspec(naked) double fun(double x) { __asm ret }
const auto funcSize = 1;
WriteFile(pipe, &fun, funcSize, ...);
答案 1 :(得分:2)
在本机代码中,您不能发送函数(代码)本身,也不能发送相同或不同的进程。 (您可以像@Abyx建议的那样尝试低级别的黑客行为,但它严重限制了代码可以执行的功能,并且可能会让您诉诸于手动编写汇编程序。)
您也无法将函数的地址发送到另一个进程,因为每个进程都有自己独立的地址空间;在另一个过程中,该地址将包含不同的数据。
解决方案是创建一个共享库(最好是动态的),它将包含可能以这种方式发送的所有函数。为每个函数分配一些标记(例如数字或名称),让DLL维护标记和地址之间的映射。然后发送标签。
答案 2 :(得分:1)
你想要实现的目标是什么?你真的想写功能吗?为什么?这不是你在C ++中可以轻易做到的事情,例如因为函数的大小没有明确定义。
您应该编写数据,即fun()
返回的数字:
const double value = fun(input);
DWORD numberOfBytesWritten;
WriteFile(pipe, &value, sizeof value, &numberOfBytesWritten, NULL);
您当然应该添加代码来检查输出。请注意,写这样的二进制数据可能很脆弱。
答案 3 :(得分:1)
由于您使用的是WinAPI,因此发送函数的本机方式是通过COM。特别是,将该函数公开为COM对象上的方法,获取COM名字对象,并发送名字对象。可以序列化Monikers并通过管道发送。另一方可以对名字对象进行反序列化并访问您的对象。
在水下,通过查找COM 运行对象表
中的对象来工作答案 4 :(得分:0)
看看这在C ++中是如何过于复杂和容易出错的(并且只适用于非常有限的一组功能),我建议你使用脚本语言。除了已经提到过的内容之外,指令缓存和DEP是你必须考虑的另外两件事。
真。将函数作为脚本传输,并在另一端运行它。救你自己的痛苦。
Angelscript看起来和感觉几乎都像C ++,所以这可能是一个可能的候选人。
现在,如果你反对这一点,因为你需要一些脚本无法做到的事情,那么知道:在这种情况下,C ++也无法做到这一点。
除了上面提到的PIC代码问题(@Abyx)以及你无法安全或可移植地知道函数大小的事实之外,你可以想象通过管道发送并以有意义的方式执行的唯一C ++函数是严格的const功能。这里,const是例如GCC的__attribute__((const))
,而不是C ++ const
关键字。
也就是说,任何这样的函数可能不会检查除其参数之外的任何值,并且除了返回值之外没有任何效果。原因很明显:不同的进程存在于不同的地址空间中,因此您引用的任何内容都是无意义的。你改变的一切都是毫无意义的 现在,这正是脚本可以安全,直接,可靠地完成的工作。考虑到你已经通过管道发送代码,开销是可以忽略不计的。