You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Stubbing场景下是否存在__attribute__((weak))的反向等效实现?

问题背景与现有实现

现有代码文件

foo_bar_run.c

#include "foo_bar_run.h"

int __attribute__((weak)) foo() 
{
    printf("foo\n");
}

int bar()
{
    printf("bar\n");
    foo();
}

foo_bar_run.h

#include <stdio.h>

extern int __attribute__((weak)) foo() ;
extern int bar();

another_main.c

#include "foo_bar_run.h"

int main(void)
{
    bar();
}

bar_test.c

#include <stdio.h>
#include "foo_bar_run.h"

int foo()
{
    printf("stubbed foo\n");
}

int main(void)
{
    bar();
}

现有编译执行效果

生成main_run程序

编译命令:
gcc another_main.c foo_bar_run.c -o main_run && ./main_run
输出:

bar
foo

生成main_test程序

编译命令:
gcc bar_test.c foo_bar_run.c -o main_test && ./main_test
输出:

bar
stubbed foo
需求说明

不修改foo_bar_run中foo的函数原型(保持int foo()定义),寻找更优雅的实现方案,可支持测试代码覆盖默认foo实现,可选完全不使用__attribute__关键字。

解决方案

你当前基于弱符号的实现本身就是C语言实现「默认实现+可打桩替换」的标准方案,已经满足要求:C语言默认全局函数就是强符号,测试代码里的foo会自动覆盖foo_bar_run中的弱符号foo,不需要额外添加属性,也不需要修改原有业务代码。
如果不想使用__attribute__关键字,推荐以下两种无侵入方案:

  • 方案1:使用链接器--wrap选项,完全不需要修改业务代码的函数定义和属性
    操作步骤:
    1. 移除foo_bar_run.h和foo_bar_run.c中所有__attribute__((weak))声明,保持foo的原型为int foo()不变
    2. 编译main_run和原有逻辑完全一致,无需额外参数:
      gcc another_main.c foo_bar_run.c -o main_run
    3. 编译测试程序时,给链接器传递wrap参数指定要打桩的函数名,同时把测试代码里的桩函数命名为__wrap_foo:
      bar_test.c修改部分:
      int __wrap_foo()
      {
          printf("stubbed foo\n");
      }
      
      编译命令:
      gcc bar_test.c foo_bar_run.c -o main_test -Wl,--wrap=foo
      该方案优势是如果桩函数需要调用原foo实现,直接调用__real_foo()即可,适合复杂打桩场景。

  • 方案2:利用链接器符号查找顺序,不需要修改任何代码的函数名和属性
    链接器查找全局符号时会按输入文件的顺序取第一个匹配的定义,利用这个特性不需要加任何属性即可实现符号覆盖:
    操作步骤:
    1. 移除foo_bar_run.h和foo_bar_run.c中所有__attribute__((weak))声明,保持foo的原型为int foo()不变
    2. 编译main_run和原有逻辑完全一致:
      gcc another_main.c foo_bar_run.c -o main_run
    3. 编译测试程序时,先把foo_bar_run编译为静态库,链接时优先传入bar_test的目标文件,再链接静态库:
      # 编译测试代码目标文件
      gcc -c bar_test.c -o bar_test.o
      # 编译业务代码目标文件并打包为静态库
      gcc -c foo_bar_run.c -o foo_bar_run.o
      ar rcs libfoobar.a foo_bar_run.o
      # 链接时先放测试代码目标文件,再放静态库
      gcc bar_test.o -o main_test -L. -lfoobar
      
    该方案优势是不需要修改测试代码的桩函数名,完全和现有测试代码写法一致。

内容的提问来源于stack exchange,提问作者Guillaume D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 20:27:03