【C语言】利用同名宏函数确定函数的被调用位置

【问题】 一个大型项目中,通用库中的对外接口函数经常会被上层业务多次调用,甚至在同一个上层业务源文件中被多次调用。此时,假设你需要对被调用接口做改动,为了确定所影响的范围,我们需要明确哪些上层业务调用了该接口。也即当前项目中有哪些源文件调用了需要改动的接口函数。


【解决方法】

    Debug 这确实是一个十分有效的方法,但为了一次debug耗费几个小时的情况你是否遇到过?既然抛出这个问题,那鄙人确实经常有这种需求。因为项目源码是百万级别,一次debug环境的准备最多耗费9小时:虚拟机选型,编译环境,源码编译(约8小时),调测环境)。显而易见,这是一个极其蠢笨的方法。 函数调用处添加打印输出信息 此方法其实是基于Debug,简便之处在于仅仅需要在项目代码中所有调用函数的地方添加打印输出信息,然后编译,一次运行即可得知当前场景下哪些业务逻辑调用了当前接口函数。显而易见,其便利之处恰恰也是其弊端:所有调用函数的地方都需要添加新代码,此种变更极可能导致整个项目的重新编译,将会付出极大的时间代价。 这确实是一个十分有效的方法,但为了一次debug耗费几个小时的情况你是否遇到过?既然抛出这个问题,那鄙人确实经常有这种需求。因为项目源码是百万级别,一次debug环境的准备最多耗费9小时(源码编译约8小时+测试环境及debug环境准备约1小时)。显而易见,这是一个极其蠢笨的方法。 宏函数替换 通过对C语言中宏函数的深入理解,你会发现合理利用宏函数可以改变原始函数的行为,我们可以尝试改变原始被调用函数的行为(限定其功能为输出当前函数被调用的源文件及行号)。具体做法请看下述实例代码:
/*
 * common_util.h
*/ 
#ifndef _COMMON_UTIL_H_
#define _COMMON_UTIL_H_

char* parameter_parser(char *str, int num);

#endif
/*
 * common_util.c
*/ 
#include "common_util.h"
#include <stdio.h>

char *parmeter_parser(char *str, int num)
{
          
   
    char *ret_str = NULL;
    // other code logic to convert and combine input params(str and num) to one string
    return ret_str;
}
/*
 * main.c
*/ 
#include "common_util.h"
#include <stdio.h>
#include <sdtlib.h>

int main()
{
          
   
    char *testStr = parameter_parser("The number of words in this string is ", 8);
    printf("%s", parmeter_parser(testStr, 9));
    return 0;
}

为了确认函数parameter_parser()在哪些源文件的哪些地方被调用,需要完成以下两个步骤:

  1. 在头文件common_util.h中定义下面的宏函数:
/*
 * common_util.h
 * Note: 因为宏定义不做类型检查(不安全),故无需关心原始函数的返回值类型及参数类型。
 * 针对函数参数,只需要使用相应个数的占位符即可,此处用a和b来占位原始函数中的char*和int类型入参。
*/ 
#define parameter_parser(a, b) (printf("Function is invokded in source file: %s at line %dh", __FILE__, __LINE__));
  1. 在源文件common_util.c中注释掉原始函数parameter_parser()
/*
 * common_util.c
*/ 
#include "common_util.h"
#include <stdio.h>

//char *parmeter_parser(char *str, int num)
//{
          
   
//    char *ret_str = NULL;
//    // other code logic to convert and combine input params(str and num) to one string
//    return ret_str;
//}

更改完成,再次编译,运行即可以通过标准输出查看到函数parameter_parser()具体的被调用信息。


【结束语】 本文所述的问题定位方法其实和博客中前期文章《》有异曲同工之处,感兴趣的同学可以参看。若有其他高见,敬请分享之!☺

经验分享 程序员 微信小程序 职场和发展