用 C 语言实现 FIFO 队列

发布于 2024-09-27 13:30:28 字数 1730 浏览 4 评论 0原文

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

...那么编译器会很高兴。但是,我担心错误消息暗示着我可能在这里做错了一些微妙的事情。所以(言归正传),谁能告诉我为什么编译器不高兴,以及是否有更好的方法来完成我在这里尝试做的事情。

For an embedded application, I am trying to implement a first-in, first-out (FIFO) queue of structs using ANSI C. The most straightforward way to do this seems to be by implementing a linked-list, so that each structure contains a pointer to the next in the queue. Hence I define the struct itself as:

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

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

So far so good. If I define pointers to the first and last items in the queue as:

QueuedAction *firstAction;
QueuedAction *lastAction;

...then I'd like to be able to add a new action to the queue by stating (for example):

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

...so on return, lastAction would be a pointer to the newly-created last action in the queue. Hence the routine for adding the action to the queue would look like:

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;
}

All would be fine and dandy, except this code won't compile. The error is at the line saying

*lastAction -> nextAction = newQueuedAction;

...where the compiler claims the item to the left of the '->' is not a valid struct. Surely, however, it must be. If in fact I do what ought to be a wholly redundant cast:

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

...then the compiler is quite happy. However, I'm worried that the error message is hinting at something subtle that I may be doing wrong here. So (to come to the point), can anyone tell me why the compiler isn't happy, and whether there is a better way to do what I'm trying to do here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

极度宠爱 2024-10-04 13:30:28

你有没有尝试过:

(*lastAction) -> nextAction = newQueuedAction;

Have you tried:

(*lastAction) -> nextAction = newQueuedAction;
半寸时光 2024-10-04 13:30:28

你也可以这样做:

(*lastAction)->nextAction

我认为这是一个操作者优先的问题。

You could also do this:

(*lastAction)->nextAction

I think it is an issue of operator pecedence.

奶茶白久 2024-10-04 13:30:28

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

它是用 C++ 编写的,但与 ANSI C 完全兼容。
如果您确实愿意,可以轻松地将其转换为 ANSI C。

源代码可通过 GIT 获取。

格茨

I've made a small library that can handle queues. "UltraQueue"

It's written in C++, but is fully compatible with ANSI C.
It can be easely converted to ANSI C if you really want to.

Source code is available through GIT.

Grtz

白鸥掠海 2024-10-04 13:30:28

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

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

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

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

翻译,以及一个很好的黑客工具,可以更好地理解指针。

行动起来吧,孩子们。

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

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 -> ...;

as

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]

看起来像这样:

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

希望有帮助,

I hope this will help you in advance.
Firstly, sorry for my english. It could have several gramatical or ortographical errors.

The problem I see in your code is mainly you mix definition of a pointer and implementation of the same one.

From ANSI C to C99, even in C++ (not tested in C#), there is a big hack using pointers could be helpful in advance: think the pointer is the first element of a vector, the [0] one.

A great site explaining this concept is: http://boredzo.org/pointers/

This hack is a bare translation, and a nice hacktool to understand better the pointers.

Get into action, boys.

The function you use to add elements into a list,

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;
}

Contains some errors. First of all, think using

*lastAction -> ...;

as

lastAction[0] -> ...;

As you see, you can't use the -> operator to access the inner elements.

The same happens here:

lastAction[0] = newQueuedAction;

You can't copy a pointer inside of a struct. lastAction, using this hack to better understanding, is not a pointer anymore -in fact, is the content of the first element in the structure the compiler has assigned into there- so you need to change this line, too, to change the pointer value:

lastAction = newQueuedAction;

Using this translation and the anotations, your code will be, now:

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;
}

The errors are, now, visible: you try to use the -> operator wrongly. That means your code will be changed in two ways:

  • Use the -> operator

It looks like this:

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;
}
  • Use the . operator with the [0] hack

It looks like this:

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;
}

And don't forget erase the == NULL code, you would encounter with a passive-aggresive programmer who defines NULL as something else. Use always braces to ensure extensibility. This line is only a recomendation of code style.

Hope it helps,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文