如何通过其他功能覆盖功能?

时间:2013-08-19 04:31:07

标签: c gcc attributes

测试代码:

void print1()
{
     printf("functon1 printing\n");
}  
//I can add other function like:
void print2()
{
    printf("function 2 printing\n");
}
// Is there a way when I call print1 in main, actually print2 works?
// I mean if print2 exist , main use print2 . else use print1.
// Hope no macro answer , any gcc attribute way is best! For I want use it in more complex code.
int main()
{
    print1();
    return 0;
}

这里我希望程序打印另一个字符串,如:“function 2 is printing”。

注意: 在某些情况下,我无法更改主要功能和print1功能!!

我希望有一种方法可以使用涵盖function1的其他功能并打印我的字符串。

我使用GCC,我对_ 属性 _知之甚少。但是,我认为gcc可以做到这一点。

是否有可能:

 any gcc attribute way is best! For I want use it in more complex code.

或者它只是gcc属性不能那样做?

有谁能举个例子?

谢谢。

3 个答案:

答案 0 :(得分:2)

如果您无法修改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(),除非重新编译,否则覆盖不会生效。< / p>

创意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()覆盖驻留在不同的源文件中,并编译到不同的共享库中。但是,覆盖不需要重新编译。

答案 1 :(得分:2)

这是一个黑客攻击,但唯一可移植(并且非常合理)的方法是使用宏预处理器。

定义print1后,定义print2

void print2(void) { printf("function 2 is printing.\n"); }

然后,在main之前,使用#defineprint1替换为print2

#define print1 print2

请注意,生产代码中的合法用途很少。它在调试时偶尔会有用。您还偶尔会看到它重新定义像malloc这样的stdlib函数。它仍然是一个黑客,应该避免。

答案 2 :(得分:1)

为了隐藏一个函数,就像在现有函数周围包装自己的函数而不替换原始函数的名称一样,请参阅我对此主题的另一个答案:https://stackoverflow.com/a/17191529/694576