如果您无法修改 和 之间的任何内容print1()
,main()
则可以更改print1()
宏的功能:
void nada (const char *s) {}
#define printf puts("function2 printing"); nada
如果允许在print1()
和之间添加代码main()
,则可以定义一个新函数,然后使用宏定义print1
为新函数。
您提出的问题的问题是您对解决方案的强加要求限制了解决问题的方法的数量。
- 您要覆盖的函数和要覆盖它的函数都在同一个源文件中。
- 你规定
print1()
不能修改。
- 您规定不能修改
print1()
调用方式。main()
所有这些限制都使得很难为您的问题提供一个很好的灵活解决方案,这就是您获得这些宏样式解决方案的原因。请允许我描述一些不受这些限制的解决方案。
想法 #1:weak
在要覆盖的函数上使用属性。然后,重新定义print1()
以检查是否存在覆盖:
extern void print2 () __attribute__((weak));
void print1 ()
{
if (print2) { print2(); return; }
puts("function1 printing");
}
由于print2()
是使用weak
属性声明的,因此您可以测试以查看是否存在它的定义。如果是,则print1()
调用它而不是做它通常会做的事情。
这允许您将所有函数定义保留在同一个源文件中,但您需要修改print1()
.
想法2:分离print1()
成main()
一个单独的文件。使用链接器的-wrap print1
选项使程序print1
在对象中解析为符号__wrap_print1
。使用此选项时,对符号的引用__real_print1
解析为原始print1
,但此解决方案不需要该功能。
$ cat main.c
extern void print1 ();
int main ()
{
print1();
}
$ cat print.c
#include <stdio.h>
void print1 () { puts("function1 printing"); }
void print2 () { puts("function2 printing"); }
void __wrap_print1 () { print2(); }
$ gcc main.c print.c && ./a.out
function1 printing
$ gcc -Wl,-wrap,print1 main.c print.c && ./a.out
function2 printing
完全不需要修改print1()
,但是可以print2()
在同一个文件中定义,print1()
除非重新编译,否则覆盖不会生效。
想法 3:如果print1()
在共享库中,您可以使用定义了替代版本的不同共享库print1()
来覆盖原始定义。您可以使用LD_PRELOAD
.
gcc main.c -o print1_test -lprint1
gcc -fPIC -c newprint1.c
gcc -shared -o newprint1.so newprint1.o
LD_PRELOAD=./newprint1.so ./print1_test
对于这个解决方案,不仅print1()
需要在不同的源文件中,而且需要编译成共享对象并链接。新的print1()
覆盖驻留在不同的源文件中并编译到不同的共享库中。但是,覆盖不需要重新编译。