You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GCC编译宏定义报错:粘贴预处理令牌无效问题求助

解决GCC下宏Token拼接编译错误问题

问题背景

我定义了如下宏:

#define GET_GENERIC_VAL(val_type, fmt_printf, prefix, suffix) \ 
val_type tmp_ ## val_type; \ 
rtc = (*(INOBJECT**)pObj)->getGeneric(meth, &(tmp_ ## val_type)); \ 
if (rtc == -1) { \ 
TRACE("Error: unable to get method for " #val_type " attribute " << attribute << " of object " << name); \ 
return -1; \ 
} \ 
sprintf(valueStr, fmt_printf, (prefix)(tmp_ ## val_type ## suffix)); 

并在switch语句中调用该宏:

switch (var_type) { 
case 'u' : { GET_GENERIC_VAL(UINT ,"%lu",UINT , + 0 ); break; } 
case 'i' : { GET_GENERIC_VAL(INT ,"%ld",INT , + 0 ); break; } 
case 's' : { GET_GENERIC_VAL(STRING ,"%s" ,const char *, + '\0' ); break; } 
case 'n' : { GET_GENERIC_VAL(NUMBER ,"%s" ,const char *, .toString()); break; } 
case 'b' : { GET_GENERIC_VAL(BYTESTRING,"%s" ,const char *, .toString()); break; } 
case 'd' : { GET_GENERIC_VAL(DATE ,"%s" ,const char *, .toString()); break; } 
case 't' : { GET_GENERIC_VAL(TIME ,"%s" ,const char *, .toString()); break; } 
default : { TRACE("Unknown type of attribute : type '" << var_type << "' for attribute '" << attribute << "' of object " << name << "."); return -1; } 
} 

使用GCC编译时出现以下错误:

error: pasting "tmp_UINT" and "+" does not give a valid preprocessing token 
error: pasting "tmp_INT" and "+" does not give a valid preprocessing token 
error: pasting "tmp_STRING" and "+" does not give a valid preprocessing token 
error: pasting "tmp_NUMBER" and "." does not give a valid preprocessing token 
error: pasting "tmp_BYTESTRING" and "." does not give a valid preprocessing token 
error: pasting "tmp_DATE" and "." does not give a valid preprocessing token 
error: pasting "tmp_TIME" and "." does not give a valid 

该代码在SUN平台编译正常,但在Linux的GCC下报错,恳请协助解决此问题。


问题原因

GCC的预处理器对##(Token拼接操作符)的规则比Sun编译器严格得多:##要求拼接前后的两个部分必须能组成一个合法的C语言Token。比如tmp_UINT是一个标识符Token,而+是运算符Token,这两个无法拼接成一个合法Token,所以GCC直接报错;而Sun编译器可能允许这种不规范的拼接,或者在预处理阶段做了额外的兼容处理。

你的宏里最后一行的tmp_ ## val_type ## suffix是问题核心:当suffix是+ 0或者.toString()时,##会强行把tmp_UINT和+、tmp_NUMBER和.拼接,这完全不符合C语言的Token规则。

解决方案

修改宏的实现,去掉suffix部分的Token拼接,把它改成直接跟在变量后面的表达式,不需要用##连接。调整后的宏如下:

#define GET_GENERIC_VAL(val_type, fmt_printf, prefix, expr_suffix) \ 
val_type tmp_ ## val_type; \ 
rtc = (*(INOBJECT**)pObj)->getGeneric(meth, &(tmp_ ## val_type)); \ 
if (rtc == -1) { \ 
TRACE("Error: unable to get method for " #val_type " attribute " << attribute << " of object " << name); \ 
return -1; \ 
} \ 
sprintf(valueStr, fmt_printf, (prefix)(tmp_ ## val_type expr_suffix)); 

然后修改switch中的调用方式,把原来的suffix参数改成直接的表达式后缀(去掉##需要的拼接形式,直接写在变量后面的内容):

switch (var_type) { 
case 'u' : { GET_GENERIC_VAL(UINT, "%lu", UINT, + 0); break; } 
case 'i' : { GET_GENERIC_VAL(INT, "%ld", INT, + 0); break; } 
case 's' : { GET_GENERIC_VAL(STRING, "%s", const char *, + '\0'); break; } 
case 'n' : { GET_GENERIC_VAL(NUMBER, "%s", const char *, .toString()); break; } 
case 'b' : { GET_GENERIC_VAL(BYTESTRING, "%s", const char *, .toString()); break; } 
case 'd' : { GET_GENERIC_VAL(DATE, "%s", const char *, .toString()); break; } 
case 't' : { GET_GENERIC_VAL(TIME, "%s", const char *, .toString()); break; } 
default : { TRACE("Unknown type of attribute : type '" << var_type << "' for attribute '" << attribute << "' of object " << name << "."); return -1; } 
} 

说明

调整后的宏把原来的suffix参数改名为expr_suffix,并且在最后一行去掉了##,直接写成tmp_ ## val_type expr_suffix——这样预处理器会先拼接出变量名(比如tmp_UINT),然后直接把expr_suffix的内容(比如+ 0)跟在变量后面,形成合法的表达式(tmp_UINT + 0),而不是强行拼接Token。这种写法既符合C语言标准,也能被GCC和Sun编译器同时兼容。

内容的提问来源于stack exchange,提问作者Pravej Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:25:18