list problem

Hi,

I'm trying to experiment with the facilities of the queue(3) framework but I'm having a compiling problem I cannot solve:

Code:
struct car_st{
  char  model[ 20 ];
  int   cc_size;
  SLIST_ENTRY(car_st) _cars;
};


...
struct car_st *current  = NULL, *previous = NULL;
...

SLIST_FOREACH_SAFE( current, &head, _cars, previous ){
    if( current->cc_size % 500 == 1 ){
      printf( "\nRemoving the car..." );
      SLIST_REMOVE( &head, current, car_st, _cars );
      free( current );
    }
  }

While I'm able to populate and traverse the list with the foreach (even safe) I cannot remove an element. I cannot see, comparing to the example in the manual, what is the problem.
The compiler provides me the following messages related to the SLIST_REMOVE line:

Code:
warning: comparison of distinct pointer types lacks a cast
error: dereferencing pointer to incomplete type
warning: initialization from incompatible pointer type

Any suggestion?
 
Did you call the initializer macro for head, and is head of that type - somehow like the following?
Code:
SLIST_HEAD(car_hd, car_st);
...
struct car_hd   head;
...
 
I've initialized the list, and in fact before the foreach-remove loop I'm able to populate and traverse the list in other ways. In particular my initialization is:

Code:
SLIST_HEAD( CAR_LIST, car_st ) head = SLIST_HEAD_INITIALIZER( head );

that is just before the declaration of current and previous. Am I doing something wrong? The strange thing is that if I remove the SLIST_REMOVE macro call everything compiles and works fine, so it should not be a problem related to the list initialization, rather to the foreach and/or remove usage.
The whole bunch of code looks like:

Code:
struct car_st{
  char  model[ 20 ];
  int   cc_size;
  SLIST_ENTRY(car_st) _cars;
};


...
SLIST_HEAD( CAR_LIST, car_st ) head = SLIST_HEAD_INITIALIZER( head );
struct car_st *current  = NULL, *previous = NULL;
...

SLIST_FOREACH_SAFE( current, &head, _cars, previous ){
    if( current->cc_size % 500 == 1 ){
      printf( "\nRemoving the car..." );
      SLIST_REMOVE( &head, current, car_st, _cars );
      free( current );
    }
  }
 
fluca1978 said:
I've initialized the list, and in fact before the foreach-remove loop I'm able to populate and traverse the list in other ways. In particular my initialization is:

Code:
struct car_st{
  char  model[ 20 ];
  int   cc_size;
  SLIST_ENTRY(car_st) _cars;
};

SLIST_HEAD( CAR_LIST, car_st ) head = SLIST_HEAD_INITIALIZER( head );

Pre-processor expansion of the above yields:

Code:
struct car_st{
  char model[ 20 ];
  int cc_size;
  struct { struct car_st *sle_next; } _cars;
};

struct CAR_LIST { struct car_st *slh_first; } head = { ((void *)0) };

You define the local variable head using the locally declared struct CAR_LIST, i.e. the scope of the variable declaration is limited to the respective block of code. When a pointer to head is used outside of this block, the compiler would complain about dereferencing pointer to incomplete type.

Try to move the initializing statement to the global (or a more global) scope. If this still errors out, then compile your code with the -E flag into a new .c file. This would give you a new valid source file with all macros expanded. Then compile this expanded file instead of the original one, and the compiler should give you a more detailed error message, indicating the exact position of the error inside the respective macros, for example:

Code:
gcc -E -c carlist.c -o carlist.E.c
gcc -c carlist.E.c

If the error messages are still not elucidating, then compile the macro expanded source using clang, which is known for its verbosity.
 
The problem is when the SLIST_REMOVE expands to the following:
Code:
if ((((&head))->slh_first) == (current)) {  
 do { ((((&head)))->slh_first) = ((((((&head)))->slh_first))->_cars.sle_next) ; }  
 while (0);

that is the deletion of the item in the head. Even moving the head declaration at a global scope did not solved the problem, and in fact the rest of the program works fine if I remove the SLIST_REMOVE macro.

The problem of the macro expansion is that there are no casts to the correct types, and if I manually rewrite the above assignment placing the correct types as follows:

Code:
if ((((&head))->slh_first) == (current)) {
           do { ((((&head)))->slh_first) =
               ( [B](struct car_st *) ( (struct CAR_LIST *)[/B] (&head)->slh_first) )->_cars.sle_next \
; }

it compiles fine. The above head-deletion is generated by the macro SLIST_REMOVE_HEAD that is defined in the queue.h as follows:

Code:
#define SLIST_REMOVE_HEAD(head, field) do {                             \
        SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);   \
} while (0)
Note that it does not include any type information, hence my problem. Since I'm sure the macro is correct (of course!) there must be a problem in the way I use it in my code.

Now, the following is my source code, if anyone sees where the problem lies...

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

struct car_st{
  char  model[ 20 ];
  int   cc_size;
  SLIST_ENTRY(car_st) _cars;
};





int
main( int argc, char** argv ){
  SLIST_HEAD( CAR_SLIST, _cars ) head = SLIST_HEAD_INITIALIZER( head );
  int i;


  struct car_st *current  = NULL, *previous = NULL;
 


  for( i = 0; i < 10; i++ ){
    current = (struct car_st *) malloc( 1 * sizeof( struct car_st ) );
    snprintf( current->model, sizeof( current->model ), "Model %d", i );
    current->cc_size = 1000 + ( i + 1 ) * 500;


    if( SLIST_EMPTY( &head ) )
      SLIST_INSERT_HEAD( &head, current, _cars );
    else
      SLIST_INSERT_AFTER( previous, current, _cars );
    

    previous = current;
  }





  printf( "\nTraversing the list and removing a single element\n" );
  current = previous = NULL;
  
  SLIST_FOREACH_SAFE( current, &head, _cars, previous ){
    if( current->cc_size % 500 == 1 ){
      printf( "\nRemoving the car..." );
      SLIST_REMOVE( &head, current, car_st, _cars );
      free( current );
      
    }
  }
  


  printf( "\nBye\n" );
}
 
Two changes make your code compile:

1. use typedef for the struct declaration starting at line #5:

Code:
typedef struct car_st{
  char  model[ 20 ];
  int   cc_size;
  SLIST_ENTRY(car_st) _cars;
} car_st;

2. at the line #17, _cars is not the kind of TYPE that the macro expects. Replace this with car_st that has been typedef'ed right before.

I did not check, whether the code does what you expect.


PS:

Sorry, I didn't check the obvious. There is only one error in your code. Simply replace at line #17 _cars by the identifier car_st, i.e. there is no need to typedef the struct car_st.
 
Back
Top