在C中实现FIFO队列

时间:2010-10-18 07:23:24

标签: c struct fifo c89

对于嵌入式应用程序,我正在尝试使用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;

...然后编译器非常高兴。但是,我担心错误消息暗示了一些微妙的东西,我可能在这里做错了。所以(为了达到目的),任何人都可以告诉我为什么编译器不满意,以及是否有更好的方法来做我想在这里做的事情。

4 个答案:

答案 0 :(得分:5)

你试过了吗?

(*lastAction) -> nextAction = newQueuedAction;

答案 1 :(得分:3)

你也可以这样做:

(*lastAction)->nextAction

我认为这是运营商的一个问题。

答案 2 :(得分:1)

我已经建立了一个可以处理队列的小型库。 “UltraQueue

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

源代码可通过GIT获得。

Grtz

答案 3 :(得分:1)

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

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

从ANSI C到C99,即使在C ++中(未在C#中测试),使用指针的大黑客也可以提前提供帮助:认为指针是向量的第一个元素, [0] 一个

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

这个hack是一个简单的翻译,是一个很好的hacktool来更好地理解指针。

开始行动,男孩们。

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

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;

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

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定义为其他东西的被动攻击性程序员。始终使用大括号来确保可扩展性。这一行只是代码风格的推荐。

希望它有所帮助,