#define C,合法字符

时间:2018-07-09 04:55:50

标签: c macros structure

有一个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。

4 个答案:

答案 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 emacsvim -并研究编辑器的文档)。您还可以使用脚本工具,例如edsedgrepawk等来帮助您进行替换。

在一个小型项目中,用->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