【问题标题】:How to Protect Against Symbol Redefinition如何防止符号重新定义
【发布时间】:2012-11-06 21:59:20
【问题描述】:

我的项目包含一个堆栈,该堆栈具有许多用户定义的类型 (typedef)。问题是这些类型定义中的许多与我们内部的类型定义相冲突。也就是说,正在使用相同的符号名称。有什么办法可以防止这种情况发生吗?

问题的根源在于,要在我们的应用程序中使用堆栈,或包装代码,视情况而定,必须包含某个头文件。该堆栈头文件又包含堆栈提供程序的类型定义文件。那就是问题所在。他们应该通过非公共包含路径包含他们的类型定义文件,但他们没有。现在,对于非常常见的名称,如BYTEWORDDWORD 等,存在各种用户定义的类型冲突。

【问题讨论】:

  • 你能在堆栈周围放一个包装器吗?
  • @WilliamMorris 这就是我想要做的,这就是为什么需要解决这些差异。
  • 问题的根源是:为什么一开始就会出现命名冲突?堆栈没有使用任何适当的命名约定,还是应用程序,或两者兼而有之?与标准 C 库是否存在冲突(又名错误)?

标签: c eclipse typedef redefinition codewarrior


【解决方案1】:

由于您可能无法轻松更改正在使用的程序堆栈,因此您必须从自己的代码开始。

首先要做的是(显然)尽可能限制全局命名空间中的名称数量。不要使用全局变量,以静态变量为例。

下一步是为您的代码模块采用命名约定。假设您在项目中有一个“输入模块”。例如,您可以在输入模块“inp”中为所有函数添加前缀。

void inp_init (void); 
void inp_get  (int input);

#define INP_SOMECONSTANT 4

typedef enum
{
  INP_THIS,
  INP_THAT,
} inp_something_t;

等等。每当这些项目在代码中的其他地方使用时,它们不仅有一个唯一的标识符,而且对读者来说它们属于哪个模块以及它们的用途也是显而易见的。因此,在修复命名空间冲突的同时,您可以获得可读性。

像上面这样的事情可能是实现正式编码标准的第一步,作为一名专业程序员,你迟早需要做的事情。

【讨论】:

  • 我认为这不能解决问题。据我了解,系统的两侧定义了具有相同名称的类型。这意味着输入堆栈不能包含系统标头,并且系统由于重新定义错误而不能包含堆栈标头。即使它们定义相同的类型,包括相反的标头也不会编译。
  • @WilliamMorris 堆栈将不包括应用程序的其余部分,这没有意义。这可能是一些通信协议栈、TCP/IP、CANopen、以太网等等。它将位于程序的较低硬件层上,而调用者是实际的应用程序。避免命名冲突的责任就在调用者身上。无论如何,问题中提供的信息有限,这并不明显。
  • 不,我知道堆栈不会包含应用程序标头。但是想象一下,您想编写一个包装器来加入这两者。您想包含堆栈头,将它们的函数转换为您的类型,然后导出转换后的函数。但是你不能,因为当你尝试将自己的头文件和堆栈头文件一起包含到包装器中时,它们会发生冲突。
  • @Lundin 感谢您的周到建议。您实现的命名约定与我在我编写的模块上实现的命名约定非常相似。我最近被一家非常小的公司聘为他们的第一位工程师,100% 致力于固件开发。情况就是这样,他们现有的大部分代码库......需要注意。
  • @JimFell 我自己对这种情况非常熟悉 :) 单独在一家小公司制定一个正式的编码标准,工作量很大,但最终还是值得的。我强烈建议使用MISRA-C 作为基础,从中挑选你喜欢的,然后作为下一步,决定代码格式和命名规则。
【解决方案2】:

我建议您定义一个包装头,以根据您自己的类型重新定义堆栈导出的所有函数和结构。然后,此标头包含在您的系统文件中,但不包含在堆栈文件中(它会发生冲突)。然后您可以编译和链接,但界面有一个弱点。如果您在重新定义中正确选择类型,它应该可以正常工作,在堆栈供应商的每次更新中都会出现维护问题...

【讨论】:

    【解决方案3】:

    我认为我暂时想出了一个合理的解决方法,但正如 Lundin 所说,长期解决方案需要一个正式的编码标准。

    基本上我所做的是将所需堆栈头文件的包含移到包含我们内部类型定义文件之前。然后,在这两个包含之间,我添加了一个编译器宏来设置一个定义的常量,这取决于堆栈的头文件单包含保护定义是否已定义。然后,我在内部类型定义文件中使用该条件定义常量作为条件编译选项,以防止重新定义冲突的数据类型。有点草率,但只能循序渐进。

    【讨论】:

    • 这使您的项目从属于堆栈,这听起来很奇怪。如果堆栈以不兼容的方式更改其定义,您可能必须更改项目的类型定义文件(我猜这是一个非常重要的文件),而不仅仅是更改我建议的包装文件。最有可能的是,不会发生此类更改,因此不会出现问题,但我更喜欢相反的依赖:-)
    • 请注意,您的解决方案还意味着您的一些源文件和它们包含的任何头文件都将使用来自项目和其他使用堆栈的类型定义(以及它们的任何头文件)进行编译include) 将使用源自堆栈的类型定义进行编译。这可能会导致难以发现的细微错误...
    • @WilliamMorris 谢谢,但这是包装代码的目的,至少就我的项目而言。实际上,堆栈可能会在以后的版本中发生变化,并且需要相应地修改包装器代码。然而,这就是所有需要改变的。我用公共和私有包含文件设置了我的包装器代码,因此使用生成的库的其他项目将不必处理任何这些混乱。
    猜你喜欢
    • 2011-04-25
    • 2016-03-25
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 2019-01-21
    • 2018-11-06
    • 2013-10-12
    相关资源
    最近更新 更多