C C++最全C语言中的面向切面编程(AOP)_c代码 aop,字节跳动正式启动2024届秋季校招

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

{
va_list args;
va_start(args, line);
int *id = (int *)va_arg(args, int *);
va_end(args);
log(“%d\n”, *id);
}

void foo(int *id)
{
//…
}

int bar(int *id, int e)
{
//…
return 0;
}


这里的代码只是一个示意,后面会给出一个实际可用的示例。


我们可以随意增加函数,这些函数都会利用同一对入口和出口函数来实现身份验证。


### 示例


下面就给出一个可用的使用函数模板实现AOP的C语言代码。



#include “mln_func.h”
#include <stdio.h>
#include <string.h>
#if defined(MLN_C99)
#include <stdarg.h>
#endif

MLN_FUNC_VOID(static, void, foo, (int *a, int b), (a, b), {
printf(“in %s: %d\n”, FUNCTION, *a);
*a += b;
})

MLN_FUNC(static, int, bar, (void), (), {
printf(“%s\n”, FUNCTION);
return 0;
})

static int my_entry(const char *file, const char *func, int line, …)
{
if (strcmp(func, “foo”)) {
printf(“%s won’t be executed\n”, func);
return -1;
}

#if defined(MLN_C99)
va_list args;
va_start(args, line);
int *a = (int *)va_arg(args, int *);
va_end(args);

printf("entry %s %s %d %d\n", file, func, line, \*a);
++(\*a);

#else
printf(“entry %s %s %d\n”, file, func, line);
#endif

return 0;

}

static void my_exit(const char *file, const char *func, int line, …)
{
if (strcmp(func, “foo”))
return;

#if defined(MLN_C99)
va_list args;
va_start(args, line);
int *a = (int *)va_arg(args, int *);
va_end(args);

printf("exit %s %s %d %d\n", file, func, line, \*a);

#else
printf(“exit %s %s %d\n”, file, func, line);
#endif
}

int main(void)
{
int a = 1;

mln\_func\_entry\_callback\_set(my_entry);
mln\_func\_exit\_callback\_set(my_exit);

foo(&a, 2);
return bar();

}


这段函数中,我们使用`MLN_FUNC`和`MLN_FUNC_VOID`来定义了两个函数,即`foo`和`bar`。两个函数的逻辑很简单,就是printf输出当前函数名以及参数值(如果有参数的话)。同时,我们也使用了`mln_func_entry_callback_set`和`mln_func_exit_callback_set`定义了两个全局回调函数,用来在函数调用开始和结束时调用。


我们可以看到,回调函数中使用`strcmp`对进入回调的函数做了过滤,仅对`foo`函数做额外处理。在入口回调中输出函数信息及第一个参数的值,随后修改参数指针指向的内存中的值。在出口回调中输出函数信息和参数值。


我们来编译一下(我们假定这个代码文件名为`a.c`):



cc -o a a.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon -std=c99 -DMLN_C99 -DMLN_FUNC_FLAG


这里:


* `/usr/local/melon`是Melon库的默认安装路径。
* `-std=c99`是启用c99。
* `-DMLN_C99`是定义一个名为`MLN_C99`的宏,这个宏用来启用函数模板组件中C99下才有的特性。
* `-DMLN_FUNC_FLAG`用来定义一个名为`MLN_FUNC_FLAG`的宏,这个宏用来启用函数模板功能。是的,如果没有这个宏,上面的那些使用`MLN_FUNC`定义的函数就是普通的C语言函数,也不会触发入口和出口回调函数的调用。


执行一下看看效果:



entry a.c foo 8 1
in __mln_func_foo: 2
exit a.c foo 8 4
bar won’t be executed


可以看到:


* 入口回调函数中,foo的第一个参数指向的内存中的值为`1`。
* 进入`foo`的实际函数逻辑中,printf输出当前的函数名为`__mln_func_foo`,以及此时看到的第一个参数的值为`2`,不再是`1`了,因为在入口回调函数中被修改了。`__mln_func_foo`这个函数执行的才是我们定义的逻辑,而`foo`是对`__mln_func_foo`的一个封装。
* 出口回调函数中,我们看到第一个参数的值变为了`4`,因为它在我们给出的函数逻辑中做了修改。
* 最后输出的是在入口回调中输出的,表示`bar`被拦截了,不会执行实际的函数功能。


最后,我们去掉`MLN_FUNC_FLAG`这个宏再次编译一次:



cc -o a a.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon -std=c99 -DMLN_C99


然后执行一下看看输出结果:





![img](https://img-blog.csdnimg.cn/img_convert/4aac9aeabcef387f09917bdd6f3f5d2a.png)
![img](https://img-blog.csdnimg.cn/img_convert/23d83e4c78b518fe8f26d6fb514dd7b0.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值