zl程序教程

您现在的位置是:首页 >  Java

当前栏目

【GCC编译优化系列】宏定义名称与函数同名是一种什么骚操作?

2023-02-18 16:28:17 时间

作者简介 *架构师李肯(全网同名)**,一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验,深耕IoT领域多年,熟知IoT领域的业务发展,深度掌握IoT领域的相关技术栈,包括但不限于主流RTOS内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、主流IoT云平台的对接、嵌入式IoT系统的架构设计等等。拥有多项IoT领域的发明专利,热衷于技术分享,有多年撰写技术博客的经验积累,连续多月获得RT-Thread官方技术社区原创技术博文优秀奖,荣获CSDN博客专家CSDN物联网领域优质创作者2021年度CSDN&RT-Thread技术社区之星2022年RT-Thread全球技术大会讲师RT-Thread官方嵌入式开源社区认证专家RT-Thread 2021年度论坛之星TOP4华为云云享专家(嵌入式物联网架构设计师)等荣誉。坚信【知识改变命运,技术改变世界】!


【GCC编译优化系列】宏定义名称与函数同名是一种什么骚操作?

如果说宏定义时C语言的精髓,那么当你看到这样的宏定义代码的时候,你一定会感慨,什么时候把这个精髓敲掉,我不要了!

文章目录

1 写在前面

有一天,在逛RT-Thread的技术论坛时,看到这么一个问题,说某份代码中,宏定义的名称竟然与函数同名。怎么回事?

你可以去参考下原贴是怎么说的:

RT-Thread-条件编译的宏和函数名一样是否不妥RT-Thread问答社区 - RT-Thread

2 问题描述

如下图所示:

因为这个同学的代码编译不过,所以他就提出了这样的疑问:究竟在C语言中宏定义名称能不能与函数名同名?

3 问题分析

为了解释这个问题,我特意找了一些伪代码。

举个例子,假如有这样的代码片段:

#define TEST_FUNC test_func
#define TEST_FUNC1

void test_func(void)
{

}

void TEST_FUNC1(void)
{

}

void jx_gatt_event_loop(void)
{
#ifdef TEST_FUNC
    TEST_FUNC(); //编译通过
#endif
#ifdef TEST_FUNC1
    TEST_FUNC1(); //编译失败
#endif
}

那么 TEST_FUNC1 这边就会报错,但是 TEST_FUNC 是不会报错的:

error: expected identifier or '(' before 'void'
  726 | void TEST_FUNC1(void)

查看一下预处理后的代码长啥样:

3664 
3665 
3666 void test_func(void)
3667 {
3668 
3669 }
3670 
3671 void (void)
3672 {
3673 
3674 }
3675 
3676 void jx_gatt_event_loop(void)
3677 {
3678 
3679     test_func();
3680 
3681 
3682     ();
3683 
3684 }
3685 

很明显TEST_FUNC1全被替换成空了,自然编译要报错。 尝试把 #define TEST_FUNC1 注释掉,编译没有问题,因为预处理后的代码长这样:

3666 void test_func(void)
3667 {
3668 
3669 }
3670 
3671 void TEST_FUNC1(void)
3672 {
3673 
3674 }
3675 
3676 void jx_gatt_event_loop(void)
3677 {
3678 
3679     test_func();
3680 
3681 
3682 
3683 
3684 }

通过上面的代码分析,以及预处理后的文件的对比,我们可以发现,宏定义的名称与函数同名,本身并没有问题;但是如果宏定义对应的函数名,没有被定义,但代码的上下文又调用了这个函数(宏),那么编译上肯定是会报错的,因为 找不到这个函数

4 问题总结

  • 先不考虑写代码的规范性,如果单从语法上考虑,看看预处理后的文件有助于帮助排查问题;
  • 在C语言的教科书中,并没有提到宏定义的名字不能与函数同名;所以这个根本就不是语法规则的限制;
  • 代码是首先是给人读的,其次才是给机器运行的;所以我个人是不太推荐这种过于隐晦的写法;可读性将大打折扣;
  • 如果在代码协作中看到这样的代码,我认为应该毫不犹豫地指正这个问题,同时要求修正这样的代码。

5 更多分享

架构师李肯 架构师李肯全网同名),一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验,深耕IoT领域多年,熟知IoT领域的业务发展,深度掌握IoT领域的相关技术栈,包括但不限于主流RTOS内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、主流IoT云平台的对接、嵌入式IoT系统的架构设计等等。拥有多项IoT领域的发明专利,热衷于技术分享,有多年撰写技术博客的经验积累,连续多月获得RT-Thread官方技术社区原创技术博文优秀奖,荣获CSDN博客专家CSDN物联网领域优质创作者2021年度CSDN&RT-Thread技术社区之星2022年RT-Thread全球技术大会讲师RT-Thread官方嵌入式开源社区认证专家RT-Thread 2021年度论坛之星TOP4华为云云享专家(嵌入式物联网架构设计师)等荣誉。坚信【知识改变命运,技术改变世界】!