我的环境是Visual Studio 2008.
我有3个不同的库。总结一下,它们的行为等同如下。
图书馆1 - 提供要注册的功能
class FunctionRegistry
{
typedef std::list<int> TListInt;
TListInt m_Params;
void * m_FPtr;
public:
FunctionRegistry(void * fptr):m_FPtr(fptr){}
FunctionRegistry& Insert(int value){m_Params.push_back(value); return *this;}
void Call();
};
void FunctionRegistry::Call()
{
/*this is the area I want to get rid of */
TListInt::iterator ite = m_Params.begin();
while (ite != m_Params.end());
{
__asm push *ite;//I want to remvoe this assmebly code somehow
++ite;//Edited after initial post
}
((void(*)())m_FPtr)();
ite = m_Params.begin();
while (ite != m_Params.end());
{
int i = 0;
__asm pop i;//I want to remvoe this assmebly code somehow
++ite;//Edited after initial post
}
/*end of area to get rid of*/
}
图书馆2 - 定义一组功能,例如
void foo(int i, int j)
{
std::cout << "foo int int " << i << " " << j << std::endl;
}
void bar(int i)
{
std::cout << "bar int " << i << std::endl;
}
void biz()
{
std::cout << "biz" << std::endl;
}
FunctionRegistry fRegFoo((void*)&foo);
fRegFoo.Insert(10).Insert(20);
FunctionRegistry fRegBar((void*)&bar);
fRegBar.Insert(10);
FunctionRegistry fRegBiz((void*)&biz);
图书馆3 - 这是上述两个库的用户,示例用法如下,
fRegFoo.Call();
fRegBar.Call();
fRegBiz.Call();
这是遗留代码,我现在正在尝试摆脱上面的汇编代码。我可以轻松地更改(通过一些API更改)我的库1以满足我的需要。但我的问题是,由于库在大量用户中的大量分发,要求他们根据库1的API更改来改变他们的用例(这里是库3)应该是我的最后选择。
现在,我正在寻求你的帮助,有没有办法用任何可能的技术改变我的库1内部,而不用改变它的API来消除这个汇编代码?
如果您认为,如果没有任何API更改就无法实现,请建议对库3进行最少代码更改的方法。
答案 0 :(得分:3)
如果您的最终用户只能按照“图书馆3”中的定义调用API,那么答案显然是肯定的。这个API的表面区域很小,如果没有任何汇编语言重新实现它将是微不足道的。这将需要更改Lib 2和Lib 1。
天真的实现是一组具有静态Call
函数的类。还有很多其他选择。
但问题是:我们没有看到你要展示的一切。如果图书馆3中提供的API很丰富,和/或如果它是漏洞,那么答案可能是从“轻松”到“放弃并找到另一份工作”的任何地方。你的电话。
注意:这个答案基于你所说的:API Lib 3不能改变,但其他一切都可以。如果你需要一个解决方案,其中Lib 2和Lib 3都没有改变,只有Lib 1中的汇编代码可以改变,请编辑你的问题来解释这个。
如果是这样,有两种选择:符合标准或依赖于实现定义的行为。 [如果它只是Windows / VS的生活可能会更容易,但是20年前我做了这件事,所以我也可以将它移植到很多种类的Unix上。绝对可以做到。]
答案 1 :(得分:1)
这摆脱了asm push&amp; pop,但最终可能会有一个很大的switch语句,最多可达256 case-statements。 (可以使用宏来生成case语句吗?)
void FunctionRegistry::Call()
{
typedef void (*_F)(...);
_F f = (_F)m_FPtr;
auto p=*m_Params.begin();
switch(m_Params.size())
{
case 0: f();break;
case 1: f(p); break;
case 2: f(p, p+1); break;
//...
//case 256: f( ...please get therapy... ); break
}
}
答案 2 :(得分:0)
不是100%肯定,但看起来你正在将值ite
推到堆栈然后再将其弹出到i
。如果这就是您要做的全部,请考虑使用std :: stack替换asm push / pop。类似的东西:
#include <stack>
//...
void FunctionRegistry::Call()
{
std::stack<TListInt::value_type> astack;
TListInt::iterator ite = m_Params.begin();
while (ite != m_Params.end());
{
astack.push(*ite);
++ite;//Edited after initial post
}
((void(*)())m_FPtr)();
ite = m_Params.begin();
while (ite != m_Params.end());
{
int i = astack.pop();
++ite;//Edited after initial post
}
}
答案 3 :(得分:0)
你看过boost :: bind吗? 像这样:
#include <boost/bind/bind.hpp>
class FunctionRegistry
{
typedef void tProcedure (void);
private:
const tProcedure proc;
public:
explicit FunctionRegistry( tProcedure proc ) : proc(proc) {}
void Call() const { proc(); }
};
const FunctionRegistry fRegFoo( boost::bind( foo, 10, 20 ) );