复杂宏编译期展开后是什么样的?当编译宏报错时,如何差错? # 例子 编译一个修改后PostgreSQL源码,elog宏原型为: ```c #define elog(elevel, ...) \ do { \ pg_prevent_errno_in_scope(); \ elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \ elog_finish(elevel, __VA_ARGS__); \ if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \ pg_unreachable(); \ } while(0) ``` 修改后: ```c #define elog(elevel, ...) \ do { \ if (no_report) \ break; \ pg_prevent_errno_in_scope(); \ elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \ elog_finish(elevel, __VA_ARGS__); \ if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \ pg_unreachable(); \ } while(0) ``` 注意,新增了两行。 编译报错。 ``` [yz@test-4 src]$ VERBOSE=1 make -j1 …… [ 11%] Building C object src/backend/CMakeFiles/libpostgresql.dir/access/aocs/aocsam_handler.c.o cd /opt2/yz/Debug/src/backend && env CCACHE_DIR="/home/yz/.ccache_postgresql_Debug" /usr/bin/ccache /opt/rh/devtoolset-8/root/usr/bin/gcc -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG -DDLSUFFIX=\".so\" -DENABLE_SSL -DENABLE_VE -DOS_LINUX -DPGXC=1 -DUSE_CMAKE -DUSE_CUR L -DUSE_OPENSSL -DXCP=1 -I/opt2/yz/src/include -I/opt2/yz/src/include/snowball -I/opt2/yz/src/include/snowball/libstemmer -I/opt2/yz/src/interfaces/libpq -D_GNU_SOURCE -fno-strict-aliasing -fwrapv -Wno-unknown-pragmas -Wno-format-truncation -Wno-stringop-truncation -msse4.1 -msse4.2 -mpopcnt -DFAKE_GB18030 -DTRACE_SORT -DWAL_DEBUG -DCACHEDEBUG -g -Werror -Wall -std=gnu11 -o CMakeFiles/libpostgresql.dir/access/aocs/aocsam_handler.c.o -c /opt2/yz/src/backend/access/aocs/aocsam_handler.c/opt2/yz/src/backend/access/aocs/aocsam_handler.c: In function ‘aocsam_parallelscan_estimate’: /opt2/yz/src/backend/access/aocs/aocsam_handler.c:593:1: error: control reaches end of non-void function [-Werror=return-type] } ``` # 排查问题 我们想知道以上宏展开后是什么样子,可以这样: ``` [yz@test-4 backend]$ cd /opt2/yz/Debug/src/backend && env CCACHE_DIR="/home/yz/.ccache_postgresql_Debug" /usr/bin/ccache /opt/rh/devtoolset-8/root/usr/bin/gcc -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG -DDLSUFFIX=\".so\" -DENABLE_SSL -DENABLE_VE -DOS_LINUX -DPGXC=1 -DUSE_CMAKE -DUSE_CURL -DUSE_OPENSSL -DXCP=1 -I/opt2/yz/src/include -I/opt2/yz/src/include/snowball -I/opt2/yz/src/include/snowball/libstemmer -I/opt2/yz/src/interfaces/libpq -I/opt2/yz/src/backend/src/PG_Glue/include -isystem -D_GNU_SOURCE -fno-strict-aliasing -fwrapv -Wno-unknown-pragmas -Wno-format-truncation -Wno-stringop-truncation -msse4.1 -msse4.2 -mpopcnt -DFAKE_GB18030 -DTRACE_SORT -DWAL_DEBUG -DCACHEDEBUG -g -Werror -Wall -std=gnu11 -o /tmp/aocsam_handler.c -E /opt2/yz/src/backend/access/aocs/aocsam_handler.c ``` 然后,我们打开/tmp/aocsam\_handler.c文件,查看宏展开后的代码: ```c static Size aocsam_parallelscan_estimate(Relation rel) { do { if (no_report) break; int __errno_location __attribute__((unused)); elog_start("/opt2/yz/src/backend/access/aocs/aocsam_handler.c", 592, __func__); elog_finish(20, "parallel SeqScan not implemented for scolumn tables"); if (__builtin_const ant_p(20) && (20) >= 20) abort(); } while(0);} ```