【问题标题】:C: Forward declaring a typedef that will be defined later for being used in declaring a function nowC: 前向声明一个 typedef 稍后将被定义用于现在声明一个函数
【发布时间】:2019-04-07 23:25:02
【问题描述】:

所以..我遇到了一些鸡和蛋的事情。

我得到了 Controller_setup.h 和 Equipment_setup.h,它们使用了另一个定义的 typedef。我可以在这里写很多关于解释为什么会这样但会避免这样做,除非有人真的想知道(尽管基本上这是试图让 Equipment_setup.c/h 中的代码与不同的控制器系统一起工作,只需让不同的 Controller_setup.h)。

在之前的控制器和编译器(控制器使用 ARM 处理器,我们使用 IAR 编译器和 IDE)上,我们开发了代码,我能够转发声明/重新定义 typedef,它可以工作。它会给我们很多警告,但它会编译和工作。

现在我们实际上正在尝试使用另一个 IDE 和编译器移植到另一个控制器(控制器使用 TriCore 处理器,我们正在使用 Code::blocks IDE 和用于 TriCore V3.4.6 的 GNU GCC 编译器)它现在正在引发错误并且不会让代码编译。

我对此很陌生,但据我了解,我应该能够随时声明该数据类型是在某处定义的,因此当我在函数声明中引用该数据类型时编译器不应该担心。

由于它在一个编译器上工作(诚然带有警告),我希望现在有一些方法可以让它工作。我认为这不像使用不同的语法那么简单吗?是否可以声明 typedef 与重新定义它?

实际上,我只是在谷歌上搜索了那个确切的问题,并且通过跟踪该线索,我现在似乎明白我想做的事情在 C11 下是允许的,但在以前的 C 标准下是不允许的。据我所知,Tricore 编译器不支持 C11,所以这可能是它过去可以工作但现在不行的原因。

但如果有人可以帮助验证这种理解,将不胜感激。

我真的不想找到解决方法,因为我担心这可能意味着对程序的结构进行相当大的修改。从长远来看可能会更好,但现在不是必须这样做的好时机。

以下是过去有效但现在无效的简化版本。我省略了 Controller_setup.h 引用 Equipment_setup.h 的部分。构建项目时首先读取 Equipment_setup.h,然后在读取 Controller_setup.h 中的重新定义时出现错误。

错误信息是:

  • 错误:[12993] typedef 'IO_link_t' 的重新定义
  • 错误:[13256] 之前声明的“IO_link_t”在这里

Equipment_setup.h

//The functions declared here are used by other .c files which
//determine how the equipment is to operate

typedef enum IO_devices_t IO_devices_t;
typedef struct IO_link_t IO_link_t;

//Declare function for checking status of a given IO device
uint8_t check_IO_device_status(IO_device_t device);

//Declare function for calibrating an input
uint8_t calibrate_input(IO_link_t*  input);

Controller_setup.h

typedef enum IO_devices_t{
  MAIN_CONTROLLER,
  REMOTE_IO_1,
  REMOTE_IO_2,
  //... will vary based on controllers being used...
  HMI_1,
  NUMBER_IO_DEVICES
} IO_devices_t;

typedef struct IO_link_t {
  IO_msg_ptr_t          IO_msg_ptr;
  uint8_t               IO_msg_size;
  IO_logic_ptr_t        IO_logic_ptr;
  //... other members as required by Equipment_setup.h ...
  //... members that vary based on the controller's SDK ...
} IO_link_t;

【问题讨论】:

    标签: c typedef forward-declaration


    【解决方案1】:

    当你这样做时:

    typedef struct IO_link_t IO_link_t;
    

    typedef 定义一个类型。您还声明 struct IO_link_t。当你这样做时:

    typedef struct IO_link_t {
      IO_msg_ptr_t          IO_msg_ptr;
      uint8_t               IO_msg_size;
      IO_logic_ptr_t        IO_logic_ptr;
      //... other members as required by Equipment_setup.h ...
      //... members that vary based on the controller's SDK ...
    } IO_link_t;
    

    定义 struct IO_link_t 之前未定义,但您还重新定义 IO_link_t 类型。这就是错误的来源。 enum 也是如此。

    您可以通过在定义 structenum 处删除 typedef 来解决此问题。

    enum IO_devices_t{
      MAIN_CONTROLLER,
      REMOTE_IO_1,
      REMOTE_IO_2,
      //... will vary based on controllers being used...
      HMI_1,
      NUMBER_IO_DEVICES
    };
    
    struct IO_link_t {
      IO_msg_ptr_t          IO_msg_ptr;
      uint8_t               IO_msg_size;
      IO_logic_ptr_t        IO_logic_ptr;
      //... other members as required by Equipment_setup.h ...
      //... members that vary based on the controller's SDK ...
    };
    

    【讨论】:

    • 感谢您的快速回复。如果我理解正确,那么我会在 Equipment_setup.h 中保留我的前向声明(??这是正确的术语,我认为不是)。我认为很重要的一个事实(我忘了提及)是 Controller_setup.h 中的结构和函数也使用这些 typedef 数据类型。
    • 但是您提供了帮助,我想我开始看到我认为事情的运作方式与实际运作方式之间的区别。我有点理解 typedef 是一种创建缩写的方法,因为它几乎就像一个宏,它使我不必在开始时键入 enum 或 struct ,但它本身并没有真正定义任何东西。但顾名思义,它是用来定义符号的。
    • 在我的原始示例中,您可以将其想象为在 Equipment_setup.h 中我正在定义一个声明,而在 Controller_setup.h 中我正在定义一个定义。所以 struct IO_link_t 有一个声明和一个定义,这很好,但是 IO_link_t 在两个地方被定义,这不是。
    • 所以,如果我对这一切的理解都正确,解决这个问题的一种方法是简单地避免 typedef 并简单地用 struct IO_link_t 替换所有??
    • @MidnightRover 你可以保留typedef,只在一个地方做。
    猜你喜欢
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 2010-10-22
    • 2013-06-02
    • 1970-01-01
    • 2016-06-19
    相关资源
    最近更新 更多