1

测试代码:

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;
}

在这里,我希望程序打印另一个字符串,例如:“函数 2 正在打印”。

注意: 在某些情况下,我无法更改 main 函数和 print1 函数!!

我希望有一种方法可以使用另一个函数覆盖function1并打印我的字符串。

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

可能吗:

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

或者它只是 gcc 属性不能做到这一点?

谁能给我一个例子?

谢谢 。

4

3 回答 3

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()除非重新编译,否则覆盖不会生效。

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

于 2013-08-19T04:42:39.810 回答
2

这是一个 hack,但唯一可移植的(并且真正合理的)方法是使用宏预处理器。

定义后print1,定义print2

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

然后,在 之前main,使用 a#define替换print1print2

#define print1 print2

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

于 2013-08-19T04:43:05.337 回答
1

要在将您自己的函数包装在现有函数周围而不替换原始函数名称的意义上隐藏函数,请参阅我关于此主题的其他答案:https ://stackoverflow.com/a/17191529/694576

于 2013-08-19T12:23:34.093 回答