2

I am trying to understand the inner workings of queue (3) macros in Freebsd. I had asked a previous question about the same topic and this is a follow up question to it.

I am trying to define a function to insert an element into the queue. queue (3) provides the macro STAILQ_INSERT_HEAD which needs a pointer to the head of the queue, type of the items in queue and the item to be inserted. My problem is that I am getting

stailq.c:31: warning: passing argument 1 of 'addelement' from incompatible pointer type

error when I try to pass the address of head to the function. The full source code is as follows:

#include <stdio.h>
#include <stdlib.h>
#include <sys/queue.h>

struct stailq_entry {
        int value;
        STAILQ_ENTRY(stailq_entry) entries;
};

STAILQ_HEAD(stailhead, stailq_entry);

int addelement(struct stailhead *h1, int e){
        struct stailq_entry *n1;
        n1 = malloc(sizeof(struct stailq_entry));
        n1->value = e;
        STAILQ_INSERT_HEAD(h1, n1, entries);
        return (0);
}
int main(void)
{
        STAILQ_HEAD(stailhead, stailq_entry) head = STAILQ_HEAD_INITIALIZER(head);
        struct stailq_entry *n1;
        unsigned i;
        STAILQ_INIT(&head);                     /* Initialize the queue. */

        for (i=0;i<10;i++){
                addelement(&head, i);
        }
        n1 = NULL;

        while (!STAILQ_EMPTY(&head)) {
                n1 = STAILQ_LAST(&head, stailq_entry, entries);
                STAILQ_REMOVE(&head, n1, stailq_entry, entries);
                printf ("n2: %d\n", n1->value);
                free(n1);
        }

        return (0);
}

As far as I can tell, head is of type struct stailhead and the addelement function also expects a pointer to struct stailhead.

STAILQ_HEAD(stailhead, stailq_entry); expands to:

struct stailhead {
  struct stailq_entry *stqh_first;
  struct stailq_entry **stqh_last; 
};

What am I missing here?

Thanks.

Community
  • 1
  • 1
Raj
  • 85
  • 1
  • 5
  • 1
    It may have something to do with the fact that you're calling the STAILQ_HEAD macro twice, thus redefining the struct. Don't do that. Just declare head as a struct of the desired type (i.e., "struct stailhead head;"). These macros are not namespace-side-effect-free. – tbert Apr 06 '12 at 06:08

1 Answers1

2

You just need to convert the first line in your main function from

STAILQ_HEAD(stailhead, stailq_entry) head = STAILQ_HEAD_INITIALIZER(head);

to

struct stailhead head = STAILQ_HEAD_INITIALIZER(head);

What's happening is that STAILQ_HEAD is a macro that defines a new type, a struct that is your data structure with the name of the first parameter with an entry type of the second parameter.

You're only supposed to call STAILQ_HEAD once to define the type of the struct - then you use that typename from thereon to create new data structures of this type.

What you did in your code sample is simple: you defined a struct named stailhead twice - once in the global scope and once in the scope of your main function. You were then passing a pointer to the local stailhead to a function that accepted the global type with the same name.

Even though both structs are identical, they're in two different storage scopes and the compiler treats them as distinct types. It's warning you that you're converting from type main::stailhead to type global::stailhead (note that I have just made up this notation, I do not believe it is canon).

You only need to define stailhead by calling the STAILQ_HEAD macro just once at the top of the file where you already did, and from thereon use struct stailhead to define an object of this type.

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • You're most welcome. Opening the header file and looking at the macro definitions is usually a good way to gain further understanding for what's taking place behind the scenes and debug macro mysteries. – Mahmoud Al-Qudsi Apr 06 '12 at 06:32