宏定义天坑记录

宏定义天坑记录

事件原委与推理过程

在编译一个使用了Protobuf的项目时出现了如下报错

sh 复制代码
[yb@VM-8-7-centos boost_searcher]$ make
g++ -o http_server http_server.cc data/raw_html.pb.cc -std=c++11 -lboost_system -lboost_filesystem -lpthread -ljsoncpp -lprotobuf 
In file included from /usr/local/protobuf/include/google/protobuf/io/coded_stream.h:132,
                 from data/raw_html.pb.h:23,
                 from index.hpp:11,
                 from searcher.hpp:10,
                 from http_server.cc:43:
/usr/local/protobuf/include/google/protobuf/io/coded_stream.h: In member function 'std::ptrdiff_t google::protobuf::io::EpsCopyOutputStream::GetSize(uint8_t*) const':
/usr/local/protobuf/include/google/protobuf/io/coded_stream.h:835:5: error: 'LOGLEVEL_4' is not a member of 'google::protobuf'; did you mean 'LOGLEVEL_INFO'?
  835 |     GOOGLE_DCHECK(ptr <= end_ + kSlopBytes);  // NOLINT
      |     ^~~~~~~~~~~~~

大致意思就是LOGLEVEL_3这玩意没被定义过,非常莫名奇妙的错误

当发现是google/protobuf下的头文件的问题,直接就头大了

编译过程中的语法错误就是两个极端,

  • 要么是自己的代码有语法错误,改一下就行
  • 但这是官方头文件文件报的语法错误啊,错误肯定不可能出现在人家,又不能调试,那没点时间和运气,这问题怕是搞不定

但我多少是有点运气在的,无意间交换了源代码中的两个头文件,居然编译过了!!!!

发现只要"searcher.hpp"定义在"HttpServer.hpp"前面,就能编过

啊,这就有点玄幻了啊

思考一下,这两个头文件内,应该是有某些依赖关系,或者跟编译的顺序有关

试了一下

这样也能过

也就是说,searcher.hpp中一定有某些东西要出现在HttpServer.hpp前面

又瞅了一眼报错

既然报错从你来,就拎着你测吧(整个头文件包含树中,这个文件处于末梢,再向末梢就是官方文件了)

放这里,诶果然又能编过了

接下来,就拿它沿着整条头文件包含树,一直向下试,看哪里出现了问题

直到到达一个log.hpp的头文件,不能再向下时

发现,当raw_html.pb.h在FATAL上时能编译过,在其下面则无法编过

啊,小东西,终于找到你了啊

如果你观察仔细,发现这个3,在前面的报错里也有点端倪

当把这个宏定义为4时,果然变成了LOGLEVEL_4

原因分析

从上面推理中可以看出,显然是这个宏定义的问题

google/protobuf的头文件中一定也有一个FATAL宏的定义,或者出现了FATAL关键词

由于C语言对宏的处理发生在预处理阶段,只进行简单无脑的文本替换

在所有的头文件中,我们都写了#pragma once,也就意味着在整个头文件包含体系中,只要出现第一次FATAL的宏定义,那以后的所有FATAL宏定义都将被忽视,一些不该被进行宏替换的地方也会被替换

自然,当我们把google/protobuf的头文件放在我们的FATAL之前,也就不会受我们的宏定义影响

总结

虽然某些时候,对宏的使用能让我们的代码简单玄妙不少,但坑也是真的坑啊

有了上面的经验教训,宏这种东西以后还是尽量少用了,毕竟不是每次都这么好运气

如果替换宏的话,大家可以尝试使用const 、static const或者枚举的语法

相关推荐
xailorliu39 分钟前
SLIC_超像素算法
c++·opencv·目标检测·机器学习·计算机视觉
苏打豆1 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
小小龙学IT2 小时前
snap7 开源西门子 S7 通信协议库深度解析
c++·开源
小溪学编程3 小时前
从 C++ 的规范变迁看语言发展
jvm·c++·面试
白山编程大哥3 小时前
Lua 中使用 C 语言的用户自定义类型——userdata
c语言·junit·lua
无敌贵点大王3 小时前
RTThread学习记录13——关于要使用一个外设,RTThread与cubemx到底要怎么配合?
c语言·stm32·学习·rtthread
phltxy3 小时前
C 语言动态内存管理:从申请空间到安全释放
c语言·开发语言·ui
ShineWinsu3 小时前
对于Redis:string类型的解析
java·c++·redis·分布式·缓存·面试·string
上位机妹子4 小时前
C 语言 数组删除指定元素(快慢指针法)
c语言·数据结构·算法
心中有你02144 小时前
【路径规划】A*寻路算法最通俗易懂讲解(C语言完整实现+详细注释)
c语言·开发语言·算法