作者简介

*架构师李肯(全网同名)**,一个专注于嵌入式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 写在前面
  • 2 问题描述
  • 3 问题分析
  • 4 问题总结
  • 5 更多分享

1 写在前面

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

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

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

2 问题描述

如下图所示:

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

3 问题分析

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

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

#define TEST_FUNC test_func
#define TEST_FUNC1void test_func(void)
{}void TEST_FUNC1(void)
{}void jx_gatt_event_loop(void)
{#ifdef TEST_FUNCTEST_FUNC(); //编译通过
#endif
#ifdef TEST_FUNC1TEST_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、华为云云享专家(嵌入式物联网架构设计师)等荣誉。坚信【知识改变命运,技术改变世界】!

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

  1. 【GCC编译优化系列】究竟什么样的代码会导致函数调用的栈溢出呢?

    [GCC编译优化系列]究竟什么样的代码会导致函数调用的栈溢出呢? 一段看似铁定栈溢出的函数代码,它一定会溢出吗? 文章目录 1 问题现场 2 简单分析 3 深入分析 3.1 假如不考虑编译优化的情况 ...

  2. 【GCC编译优化系列】GCC链接失败的错误提示 undefined reference to ‘xxx‘ 可能还有一种情况你没注意到?

    文章目录 1 写在前面 2 问题描述 2.1 问题现场 2.2 快速排查 2.3 判断问题 3 知识点突破 3.1 场景复现 3.2 深入分析 3.3 涨点新知识 4 经验总结 5 参考链接 6 更多 ...

  3. 【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  4. GCC编译优化指南【作者:金步国】

    GCC编译优化指南[作者:金步国] GCC编译优化指南 作者:金步国 版权声明 本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布.任何人都可以自由使用.转载.复制和再分 ...

  5. Android编译优化系列-kapt篇

    一.背景 本文是编译优化系列文章之 kapt 优化篇,后续还会有 build cache, kotlin, dex 优化等文章,敬请期待.本文由Client Infra->Build Infra ...

  6. 关于gcc扩展中的宏定义中用 # 和 ##

    关于gcc扩展中的宏定义中用 "#" 和 "##" 今天测试了宏定义中的 "#" 和 "##" 的区别. 结果如下: & ...

  7. 编译阶段打印宏定义的内容

    背景 总所周知,代码量稍微大一点的C/C++项目的一些宏定义都会比较复杂,有时候会嵌套多个#if/#else判断分支和一堆#ifdef/#undef让你单看代码的话很难判断出宏定义的具体内容. 如果有 ...

  8. 用宏定义代替printf函数

    问题提出 有时候我们想用宏定义来决定是编译debug版本的代码还是release的代码,dubug版本的代码会通过printf打印调试信息,release版本的代码则不会.我们总不能对每一条print ...

  9. 函数式宏定义与普通函数的区别?C语言宏定义和宏定义函数 ?

    http://www.jb51.net/article/41869.htm 尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧.传参.传返回 ...

最新文章

  1. 《Akka应用模式:分布式应用程序设计实践指南》读书笔记1
  2. Spring中RedirectAttributes的用法
  3. Matlab中配置LibSVM 总结
  4. oracle未过账是什么意思,EBS R12 GL过帐问题(急)
  5. [Java in NetBeans] Lesson 06. Custom classes
  6. github 开源 代码 学习 集合(转载)
  7. 面向对象设计启发规则
  8. angularjs启动项目报ERROR in AppModule is not an NgModule解决方法
  9. 【JZOJ4920】【NOIP2017提高组模拟12.10】降雷皇
  10. vue scss @font-face 路径问题
  11. 你是否适合当一个Java程序员?一文看清
  12. Spring框架 初步入门猜想
  13. 微软回应法国指责Win10过度收集隐私数据:将更新隐私声明
  14. JZ29 最小的K个数 剑指Offer 40
  15. 2020 恒生电子 面经
  16. c++编写植物大战僵尸
  17. 用于机器学习的数据库--UCI数据库
  18. 如何一下清空微信好友_微信清理好友方法|微信如何正确清理已删除你的微信好友 微信清理好友方法介绍_东坡下载...
  19. 大数据就业前景真的那么好吗
  20. 一键抠图Portrait Matting人像抠图 (C++和Android源码)

热门文章

  1. TLC2543和mini2440通信的速率
  2. 基于SpringBoot的宿舍管理系统
  3. Bootstrap模板-Minimal.2.1.1
  4. Excel宏被禁用解决办法
  5. linux权限管理详解
  6. 计算机外存是ram硬盘还是,都是存储器,但RAM、ROM、闪存、硬盘怎么分?
  7. pandas计算方差,平均值,分位数,中位数
  8. 迅雷CTO李金波:致创业者的一封信
  9. linux deploy连接ssh失败,ubuntu – Jenkins发布ssh成功连接服务器但是put文件失败
  10. 2021年全球支付现状及发展趋势分析:亚太电子商务数字支付将超过3.1万亿美元[图]