有一种方法可以用C宏代替普通的C代码

问题描述

| 我想在C文件上运行工具x并获取代码。 (如果我们只能做更好的宏功能)。我知道
gcc -E
,但这也将所有包含都包含在一个文件中。 基本上,我想对重复的代码使用一些C宏,但不希望最终代码包含任何宏,因为它们不适合项目。     

解决方法

        使用您选择的脚本语言,注释掉所有
#include
,然后运行
gcc -E -Wp,-P,-C,-CC foo.c
,然后取消注释
#include
。或者,您可以将
#include
替换为以
#
开头的字符串,例如
include#
@include
;可能性是无止境。使用
@
而不是
#
的方法使您可以完全控制哪些预处理程序指令可以进行扩展和不进行扩展...用...8ѭ对不需要的预处理程序代码进行编码,然后脚本仅运行
gcc -E
然后进行更改
@
#
。但是,我认为最好反过来做,使用特殊标记(例如
@
)来表示可扩展宏。然后脚本会将前5个前导字符变成另一个(例如16个),然后将标记(例如8个)变成5个,运行0个,然后将16个(或任何其他值)变回5个。
-Wp
指定预处理器选项。
-P
表示不生成行指令,
-C
表示不删除注释,
-CC
表示不删除宏生成的注释-这意味着代码生成宏中的注释将保留在输出中。要确定所有可用的预处理器选项(有很多,大多数都不感兴趣),请运行
gcc -Wp,--help anyfile.c
……这就是我想出的答案(首先运行
gcc --help
以找到
-Wp
选项之后)。 (知道如何发现事物比了解事物更重要。)     ,        如何将分隔符放在ѭ1after列表之后的代码中,以便您可以手动删除包含文件扩展名,但在运行
gcc -E
之后保留宏扩展名不变? 就像是:
#include <one>
#include <two>
void delete_everything_above_and_put_includes_back(); // delimeter
#define MACRO(X) ...
//rest of the code
我不知道可扩展宏但不扩展
#include
s的工具...     ,        我决定添加另一个答案,因为它完全不同。 您没有考虑过将宏扩展到项目源存储库中的技巧,而是考虑使用
const
变量和
inline
函数作为替代方法吗? 基本上,这些就是在项目中“不赞成”宏的原因。 您必须记住,
inline
只是一个“建议”(即:实际上可能没有内联函数),
const
将使用内存而不是常量常量(嗯,取决于编译器,好的编译器会优化),但这会做两件事: 保持您的代码符合项目编码标准(这总是一件好事,至少在政治上(如果不一定在技术上) 不需要代表您执行其他隐藏脚本或操作来保持代码的可重用性和可维护性(我假设您要使用宏以避免重复的代码,对吗?) 因此,请牢记这一点,作为一种选择。     ,解决问题的方法可能是:“编写一个宏,然后将其替换为等效的函数,然后将其丢弃”,您可以使用原型函数式宏。它们有一些局限性,必须谨慎使用。但是它们的工作方式几乎与函数相同。
#define xxPseudoPrototype(RETTYPE,MACRODATA,ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA

xxPseudoPrototype(float,xxSUM_data,int x; float y; );
xxSUM_data xxsum;
#define SUM_intfloat(X,Y) ( xxsum = (xxSUM_data){ .x = (X),.y = (Y) },\\
    xxsum.xxmacro__ret__ = xxsum.x + xxsum.y,\\
    xxsum.xxmacro__ret__)
我已经在这里解释了细节(主要是第4节,类似于函数的宏): 宏伪造功能 第一行定义了一个宏,该宏可用于声明宏的伪原型。 第二行使用提供这种伪原型的宏。它定义了所需类型的“正式”参数。它依次包含宏所需的\“ return \”类型,将保存宏参数的结构的名称,最后是宏的参数(带有类型!)。我更喜欢称它们为伪参数。 第三行是强制性声明,它使“真实”成为伪参数。它声明了一个结构,必须编写。它定义了一个结构,其中包含伪参数的“真实”版本。 最后,将宏本身定义为由逗号运算符分隔的表达式的链接列表。第一个操作数用于将宏的参数“加载”到“ real”类型的参数中。最后一个操作数是“返回值”,它也具有所需的类型。 观察到编译器对类型进行正确且透明的诊断。 (但是,如链接中所述,有必要对这些结构有所注意)。 现在,如果您可以将宏的所有语句收集为以逗号分隔的函数调用链,那么您可以根据需要获取类似函数的宏。 而且,由于已经定义了参数列表,因此可以轻松将其转换为实函数。类型检查已经完成,因此一切正常。 在上面的示例中,您必须用以下其他行替换所有行(第一行除外):
#define xxPseudoPrototype(RETTYPE,ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA

float SUM_intfloat(int x,float y) {                       /* (1) */
   xxPseudoPrototype(float,int x; float y; ); /* (2) */
   xxSUM_data xxsum;                                       /* (2) */
   return                                                  /* (3) */
     ( xxsum = (xxSUM_data){ .x = x,.y = y },/* (4) (5) (6) */
         xxsum.xxmacro__ret__ = xxsum.x + xxsum.y,/* (5) (6) */
         xxsum.xxmacro__ret__)                             /* (6) */ 
    ;                                                      /* (7) */
 }                                                         /* (8) */
更换将遵循固定程序: (1)宏头变成函数头。分号(;)替换为逗号(,)。 (2)声明行在函数体内移动。 (3)添加了“ return”字样。 (4)宏参数X,Y被函数参数x,y取代。 (5)所有结尾的\“ \\\”被删除。 (6)所有中间计算和函数调用均保持不变。 (7)添加了分号。 (8)关闭功能体。 问题:尽管这种方法可以解决您的需求,但是请注意,该函数已重复了其参数列表。这不好:伪原型和重复项必须删除:
float SUM_intfloat(int x,float y) { 
   return  
     ( x + y )
    ;  
 }