【问题标题】:Implementing a FIFO queue in C在 C 中实现 FIFO 队列
【发布时间】:2010-10-18 07:23:24
【问题描述】:

对于嵌入式应用程序,我正在尝试使用 ANSI C 实现结构的先进先出 (FIFO) 队列。最直接的方法似乎是实现链表,这样每个结构都包含一个指向队列中下一个的指针。因此,我将结构本身定义为:

typedef enum { LED_on, LED_off, etc } Action;
typedef struct Queued_Action QueuedAction;

struct Queued_Action
{
    Action       action;
    int          value;
    QueuedAction *nextAction;
};

到目前为止一切顺利。如果我将指向队列中第一项和最后一项的指针定义为:

QueuedAction *firstAction;
QueuedAction *lastAction;

...然后我希望能够通过说明(例如)向队列中添加新操作:

if (!add_action_to_queue(LED_on, 100, &lastAction))
     printf("Error!\n);

...所以返回时,lastAction 将是指向队列中新创建的最后一个动作的指针。因此,将动作添加到队列的例程如下所示:

int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
{
    QueuedAction *newQueuedAction;

    // Create a new action in memory
    if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
        return 0;

    // Make the old 'lastAction' point to the new Action, 
    // and the new Action to point to NULL:
    *lastAction -> nextAction = newQueuedAction;
    newQueuedAction -> nextAction = NULL;
    newQueuedAction -> action = newAction;
    newQueuedAction -> value = newValue;

    // Designate the new Action as the new lastAction:
    *lastAction = newQueuedAction;
    return 1;
}

一切都会好起来的,只是这段代码无法编译。错误出现在

*lastAction -> nextAction = newQueuedAction;

...编译器声称'->'左侧的项目不是有效的结构。当然,它必须是。如果事实上我做了应该是完全多余的演员:

fakeAction = (QueuedAction *)(*lastAction);
fakeAction -> nextAction = newQueuedAction;

...那么编译器就很高兴了。但是,我担心错误消息暗示我在这里可能做错了一些微妙的事情。所以(直截了当),谁能告诉我为什么编译器不高兴,以及是否有更好的方法来做我想做的事情。

【问题讨论】:

    标签: c struct fifo c89


    【解决方案1】:

    你试过了吗:

    (*lastAction) -> nextAction = newQueuedAction;
    

    【讨论】:

    • 谢谢你们;这确实是运算符优先级的问题,将括号放在 (*lastAction) 周围即可解决问题。
    【解决方案2】:

    你也可以这样做:

    (*lastAction)->nextAction
    

    我认为这是操作员的操作问题。

    【讨论】:

    • 是的,那是运算符优先级在咬你。
    【解决方案3】:

    我制作了一个可以处理队列的小型库。 "UltraQueue"

    它是用 C++ 编写的,但与 ANSI C 完全兼容。 如果你真的想,它可以很容易地转换为 ANSI C。

    源代码可通过 GIT 获得。

    格子

    【讨论】:

      【解决方案4】:

      我希望这会提前帮助您。 首先,对不起我的英语。它可能有几个语法或拼写错误。

      我在您的代码中看到的问题主要是您混合了指针的定义和相同的实现。

      从 ANSI C 到 C99,即使在 C++ 中(未在 C# 中测试),也有一个使用指针的大技巧可能会有所帮助:认为指针是向量的第一个元素, [0] 一个

      解释这个概念的好网站是:http://boredzo.org/pointers/

      这个 hack 是一个简单的翻译,是一个很好的 hack 工具,可以更好地理解指针。

      开始行动吧,孩子们。

      用于将元素添加到列表中的函数,

      int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
      {
          QueuedAction *newQueuedAction;
      
          // Create a new action in memory
          if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
              return 0;
      
          // Make the old 'lastAction' point to the new Action, 
          // and the new Action to point to NULL:
          *lastAction -> nextAction = newQueuedAction;
          newQueuedAction -> nextAction = NULL;
          newQueuedAction -> action = newAction;
          newQueuedAction -> value = newValue;
      
          // Designate the new Action as the new lastAction:
          *lastAction = newQueuedAction;
          return 1;
      }
      

      包含一些错误。首先,考虑使用

      *lastAction -> ...;
      

      作为

      lastAction[0] -> ...;
      

      如您所见,您不能使用 -> 运算符来访问内部元素。

      同样的情况发生在这里:

      lastAction[0] = newQueuedAction;
      

      您不能在结构内复制指针。 lastAction,使用这个 hack 来更好地理解,它不再是一个指针 - 事实上,它是编译器分配给那里的结构中第一个元素的内容 - 所以你需要改变这一行,也可以更改指针值:

      lastAction = newQueuedAction;
      

      使用此翻译和注释,您的代码现在将是:

      int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
      {
          QueuedAction *newQueuedAction;
      
          // Create a new action in memory
          if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
              return 0;
      
          // Make the old 'lastAction' point to the new Action, 
          // and the new Action to point to NULL:
          lastAction[0] -> nextAction = newQueuedAction;
          newQueuedAction -> nextAction = NULL;
          newQueuedAction -> action = newAction;
          newQueuedAction -> value = newValue;
      
          // Designate the new Action as the new lastAction:
          lastAction[0] = newQueuedAction;
          return 1;
      }
      

      错误现在是可见的:您尝试错误地使用 -> 运算符。这意味着您的代码将以两种方式更改:

      • 使用 -> 运算符

      看起来像这样:

      int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
      {
          QueuedAction *newQueuedAction;
      
          // Create a new action in memory
          if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
              return 0;
      
          // Make the old 'lastAction' point to the new Action, 
          // and the new Action to point to NULL:
          lastAction -> nextAction = newQueuedAction;
          newQueuedAction -> nextAction = NULL;
          newQueuedAction -> action = newAction;
          newQueuedAction -> value = newValue;
      
          // Designate the new Action as the new lastAction:
          lastAction = newQueuedAction;
          return 1;
      }
      
      • . 运算符与 [0] hack
      • 结合使用

      看起来像这样:

      int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
      {
          QueuedAction *newQueuedAction;
      
          // Create a new action in memory
          if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
              return 0;
      
          // Make the old 'lastAction' point to the new Action, 
          // and the new Action to point to NULL:
          lastAction[0].nextAction = newQueuedAction;
          newQueuedAction[0].nextAction = NULL;
          newQueuedAction[0].action = newAction;
          newQueuedAction[0].value = newValue;
      
          // Designate the new Action as the new lastAction:
          lastAction = newQueuedAction;
          return 1;
      }
      

      并且不要忘记删除 == NULL 代码,您会遇到将 NULL 定义为其他内容的被动攻击型程序员。始终使用大括号以确保可扩展性。此行只是代码风格的推荐。

      希望对你有帮助,

      【讨论】:

        猜你喜欢
        • 2023-04-03
        • 2012-04-30
        • 2017-04-08
        • 2014-08-24
        • 1970-01-01
        • 1970-01-01
        • 2020-03-09
        • 1970-01-01
        • 2013-11-15
        相关资源
        最近更新 更多