我使用一个库来定义脚本语言的内部除法运算符。不幸的是,它不会对除数进行零检查。这导致了很多令人头疼的问题。我知道运营商的签名。
double ScriptClass::Divide(double&, double&);
可悲的是,它甚至不是C函数。有什么方法可以让我的应用程序使用我自己的Divide
函数而不是ScriptClass::Divide
函数吗?
编辑:
我知道dlopen(NULL,..)
并用用户定义的函数替换“C”函数。这可以为类成员函数完成(不使用错位名称)吗?
答案 0 :(得分:3)
LD_PRELOAD是你的朋友。例如,请参阅:
https://web.archive.org/web/20090130063728/http://ibm.com/developerworks/linux/library/l-glibc.html
答案 1 :(得分:3)
一般来说,这取决于程序员,而不是基础除法运算符,以防止除零。如果你将零除以很多,这似乎表明所使用的算法存在可能的缺陷。考虑重新编写算法,或者如果这不是一个选项,则保护调用除以零检查。您甚至可以在protected_divide
类型函数中执行此操作。
所有这一切,假设因为它看起来像一个C ++函数,你有一个C ++库编译了你用来构建你的应用程序的所有相同的选项,所以名称修改匹配你可能能够将函数重新定义为.so
并使用LD_PRELOAD
强制加载。如果您静态链接,我认为您可以在自己的.o
文件中创建该函数,并在库本身之前链接该文件将导致链接器获取您的版本。
答案 2 :(得分:1)
正如其他人所提到的,各种链接器和动态链接器实现将提供看起来像这样的解决方案。
但是,如果您使用任何这些功能(GNU ld的--wrap,ld.so的LD_PRELOAD等)重新定义一个C ++函数,您违反了单一定义规则,因此调用未定义的行为。
在编译库时,允许编译器以其认为合适的任何方式内联所讨论的函数,这意味着在所有情况下都可能不会调用函数的重新定义。
请考虑以下代码:
class A
{
public:
void foo();
void bar();
};
void A::foo()
{
std::cout << "Old version.\n";
}
void A::bar()
{
foo();
}
GCC 4.5,当使用-O3调用时,实际上会决定将foo()的定义内联到bar()中。如果你以某种方式让你的链接器用你自己的定义替换A :: foo()的这个定义,A :: bar()将仍输出字符串“Old version。\ n”。< / p>
所以,总而言之:不要。
答案 3 :(得分:0)
我没有想到,但是你可以使用ld的--wrap
选项让特定的函数根据其旧名称给出一个新名称。然后,您可以编写它的新版本,如果愿意,也可以转发到旧版本。
此处快速概述:
我过去曾使用它来挂钩malloc
(等),而不必重新编译运行时库,虽然这不是在Linux上(它是一个没有运行时加载的嵌入式事物)。我没有使用它来包装C ++函数,但是如果你能以某种方式处理C ++调用约定,并且你可以使用原始函数的错位名称创建一个函数,并让编译器接受对某个丑陋函数的调用用它中有趣的字符命名...我不明白为什么它不可能使其成功。
答案 4 :(得分:0)
短暂Q, 你不能用自己的代码包装课程吗? 一开始会有些头痛,但之后你可以简化很多功能。
(或者甚至只用宏包裹函数)