复杂宏编译期展开后是什么样的?当编译宏报错时,如何差错?

例子

编译一个修改后PostgreSQL源码,elog宏原型为:

snippet.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)

修改后:

snippet.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文件,查看宏展开后的代码:

snippet.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);}