有一个C结构
struct a
{
int val1,val2;
}
我对代码进行了更改
struct b
{
int val2;
}
struct a
{
int val1;
struct b b_obj;
}
现在,其他C文件中val2的用法类似于a_obj->val2;
。
我想替换其声明用法,并且有很多声明,因此我在头文件中定义了一个宏,其中struct a的定义如下:
#define a_obj->val2 (a_obj->b_obj.val2)
不起作用。 ->
在宏定义#define
的标识符部分中是非法的吗?
有人可以告诉我我哪里错了吗?
根据@Basile的建议进行编辑-
这是旧版源代码,非常庞大的项目。不确定LOC。
我想进行此类更改,因为我想使其更具模块化。
例如,我想用相同的名称对结构的相似字段进行分组,这就是我要创建另一个结构B的原因,该结构B既与B功能相关,又与A相同。
我不能使用其他文本编辑器的“查找替换”功能,我正在使用VIM。
答案 0 :(得分:6)
这种宏魔术会很快给您带来麻烦,
因为它会使您的源代码变得不可读且脆弱(请使用Basile进行措辞)。
但这应该可以满足您的描述。
struct b
{
int val2m;
}
struct a
{
int val1;
struct b b_obj;
}
#define val2 b_obj.val2m
诀窍是为struct声明中的实际标识符赋予新名称(val2m
),以便将所有其他代码使用的名称转换为魔术别名,
然后可以包含修改后的访问权限,以通过附加引入的内部结构绕行。
这仅是一种创可贴,用于必须在现有代码的后台更改一些引用的麻烦情况。仅在没有机会彻底重构代码的情况下才使用它。 (“创可贴”,StoryTeller的相应图片,鸣谢)。
我明确建议您查看Basiles的答案,以获得更清洁的“面向未来”的方式。这是避免使用此宏魔术所预测的麻烦的方法。如果您没有很好的理由强迫使用它。
答案 1 :(得分:4)
如其他解释所述,preprocessor仅适用于令牌,并且您只能#define
命名。阅读documentation of cpp
和C11标准n1570。
您要做的是非常丑陋(在少数情况下值得这样做)。它使您的代码混乱,不可读且易碎。
学习更好地使用源代码编辑器(您可能有一些交互式替换,或用regexp -s进行交互式替换;如果没有,请切换到更好的编辑器,例如GNU emacs或vim
-并研究编辑器的文档)。您还可以使用脚本工具,例如ed
,sed
,grep
,awk
等来帮助您进行替换。
在一个小型项目中,用->val2
(或.val2
)替换与{em>相关的出现的->b_obj.val2
(或.b_obj.val2
)非常容易,即使您有一百个。这样可以使您的代码更具可读性。不要忘记使用某些version control系统(以同时保留新旧版本的代码)。
在至少一百万行源代码的大型项目中,您可能会问如何找到给定类型的val2
字段用法的每一次出现(但您可能应该命名为val2
足以使它的大多数出现相关;换句话说,请注意字段的命名)。这是一个非常不同的问题(例如,您可以编写一些GCC plugin来查找此类事件并帮助您替换相关的事件)。
如果要重构旧的大型遗留代码,则需要确保其可读性,并且不要花哨的宏技巧。例如,您可以添加一些static inline
函数来访问该字段。然后可能有必要使用一些更好的工具(例如,编译器插件,某种C解析器等)来帮助您进行重构。
保持人类开发人员可读的源代码。否则,您将在脚上开枪。您想要做的事情是不合理的,它会降低代码库的可读性。
我不能使用其他文本编辑器的“查找替换”功能,我正在使用VIM。
vim
是可编写脚本的(例如,在lua
中)并且接受插件(因此,如果交互式替换还不够,请考虑编写一些vim
插件或脚本来为您提供帮助),并且功能强大查找替换正则表达式工具。您可能还会使用一些脚本组合来帮助您。在许多情况下,它们就足够了。如果不是,则应说明原因。
此外,您可以临时将val2
的{{1}}字段替换为唯一的名称,例如struct a
(或适当的名称,使一些唯一的“看起来很随机”的名称很容易)。然后,您运行您的 full 构建(例如,在val2_3TYRxW1PuK7
之后)。编译器会在需要替换用作make clean
字段的val2
的每个位置发出错误消息(但不介意其他任何出现的struct a
名称)其他目的)。这可能对您有很大帮助-一旦您纠正了代码以消除所有错误-(尤其是在与某些编辑器脚本结合使用时),因为那样的话,您只需要在各处使用val2
替换val2_3TYRxW1PuK7
。 / p>
答案 2 :(得分:2)
->
在#define中是非法的吗?
是的
#define
标识符只能是字母,数字或下划线。
答案 3 :(得分:1)
宏定义必须是常规标识符,因此您不能使用任何特殊字符,例如-
或>
。
我认为可能是您可以使用工会,例如:
struct b
{
int val2;
}
struct a
{
int val1;
union {
struct b b_obj;
int val2;
}
}
因此您仍然可以使用a_obj->val2
。