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.
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.
Related
I'm coming from Java and I'm trying to implement a doubly linked list in C as an exercise. I wanted to do something like the Java generics where I would pass a pointer type to the list initialization and this pointer type would be use to cast the list void pointer but I'm not sure if this is possible?
What I'm looking for is something that can be stored in a list struct and used to cast *data to the correct type from a node. I was thinking of using a double pointer but then I'd need to declare that as a void pointer and I'd have the same problem.
typedef struct node {
void *data;
struct node *next;
struct node *previous;
} node;
typedef struct list {
node *head;
node *tail;
//??? is there any way to store the data type of *data?
} list;
Typically, the use of specific functions like the following are used.
void List_Put_int(list *L, int *i);
void List_Put_double(list *L, double *d);
int * List_Get_int(list *L);
double *List_Get_double(list *L);
A not so easy for learner approach uses _Generic. C11 offers _Generic which allows for code, at compile time, to be steered as desired based on type.
The below offers basic code to save/fetch to 3 types of pointers. The macros would need expansion for each new types. _Generic does not allow 2 types listed that may be the same like unsigned * and size_t *. So there are are limitations.
The type_id(X) macros creates an enumeration for the 3 types which may be use to check for run-time problems as with LIST_POP(L, &d); below.
typedef struct node {
void *data;
int type;
} node;
typedef struct list {
node *head;
node *tail;
} list;
node node_var;
void List_Push(list *l, void *p, int type) {
// tbd code - simplistic use of global for illustration only
node_var.data = p;
node_var.type = type;
}
void *List_Pop(list *l, int type) {
// tbd code
assert(node_var.type == type);
return node_var.data;
}
#define cast(X,ptr) _Generic((X), \
double *: (double *) (ptr), \
unsigned *: (unsigned *) (ptr), \
int *: (int *) (ptr) \
)
#define type_id(X) _Generic((X), \
double *: 1, \
unsigned *: 2, \
int *: 3 \
)
#define LIST_PUSH(L, data) { List_Push((L),(data), type_id(data)); }
#define LIST_POP(L, dataptr) (*(dataptr)=cast(*dataptr, List_Pop((L), type_id(*dataptr))) )
Usage example and output
int main() {
list *L = 0; // tbd initialization
int i = 42;
printf("%p %d\n", (void*) &i, i);
LIST_PUSH(L, &i);
int *j;
LIST_POP(L, &j);
printf("%p %d\n", (void*) j, *j);
double *d;
LIST_POP(L, &d);
}
42
42
assertion error
There is no way to do what you want in C. There is no way to store a type in a variable and C doesn't have a template system like C++ that would allow you to fake it in the preprocessor.
You could define your own template-like macros that could quickly define your node and list structs for whatever type you need, but I think that sort of hackery is generally frowned upon unless you really need a whole bunch of linked lists that only differ in the type they store.
C doesn't have any runtime type information and doesn't have a type "Type". Types are meaningless once the code was compiled. So, there's no solution to what you ask provided by the language.
One common reason you would want to have a type available at runtime is that you have some code that might see different instances of your container and must do different things for different types stored in the container. You can easily solve such a situation using an enum, e.g.
enum ElementType
{
ET_INT; // int
ET_DOUBLE; // double
ET_CAR; // struct Car
// ...
};
and enumerate any type here that should ever go into your container. Another reason is if your container should take ownership of the objects stored in it and therefore must know how to destroy them (and sometimes how to clone them). For such cases, I recommend the use of function pointers:
typedef void (*ElementDeleter)(void *element);
typedef void *(*ElementCloner)(const void *element);
Then extend your struct to contain these:
typedef struct list {
node *head;
node *tail;
ElementDeleter deleter;
ElementCloner cloner;
} list;
Make sure they are set to a function that actually deletes resp. clones an element of the type to be stored in your container and then use them where needed, e.g. in a remove function, you could do something like
myList->deleter(myNode->data);
// delete the contained element without knowing its type
create enum type, that will store data type and alloc memory according to this enum. This could be done in switch/case construction.
Unlike Java or C++, C does not provide any type safety. To answer your question succinctly, by rearranging your node type this way:
struct node {
node* prev; /* put these at front */
node* next;
/* no data here */
};
You could then separately declare nodes carrying any data
struct data_node {.
data_node *prev; // keep these two data members at the front
data_node *next; // and in the same order as in struct list.
// you can add more data members here.
};
/* OR... */
enter code here
struct data_node2 {
node node_data; /* WANING: this may look a bit safer, but is _only_ if placed at the front.
/* more data ... */
};
You can then create a library that operates on data-less lists of nodes.
void list_add(list* l, node* n);
void list_remove(list* l, node* n);
/* etc... */
And by casting, use this 'generic lists' api to do operation on your list
You can have some sort of type information in your list declaration, for what it's worth, since C does not provide meaningful type protection.
struct data_list
{
data_node* head; /* this makes intent clear. */
data_node* tail;
};
struct data2_list
{
data_node2* head;
data_node2* tail;
};
/* ... */
data_node* my_data_node = malloc(sizeof(data_node));
data_node2* my_data_node2 = malloc(sizeof(data_node2));
/* ... */
list_add((list*)&my_list, (node*)my_data_node);
list_add((list*)&my_list2, &(my_data_node2->node_data));
/* warning above is because one could write this */
list_add((list*)&my_list2, (node*)my_data_node2);
/* etc... */
These two techniques generate the same object code, so which one you choose is up to you, really.
As an aside, avoid the typedef struct notation if your compiler allows, most compilers do, these days. It increases readability in the long run, IMHO. You can be certain some won't and some will agree with me on this subject though.
I was looking at Glibc codes. Some codes of glibc's queue caught my attention. I couldn't give a meaning to this struct definition. This struct doesn't have a name. Why? How does it work?
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
Source
That is actually a preprocessor macro, that could be expanded (most probably with trailing name) somewhere else.
In the comments at the start of that header file there is a reference to queue(3) man page that contains more details on that and other macros:
The macro LIST_ENTRY declares a structure that connects the elements
in the list.
And an example of use:
LIST_HEAD(listhead, entry) head = LIST_HEAD_INITIALIZER(head);
struct listhead *headp; /* List head. */
struct entry {
...
LIST_ENTRY(entry) entries; /* List. */
...
}
*n1, *n2, *n3, *np, *np_temp;
LIST_INIT(&head); /* Initialize the list. */
n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
LIST_INSERT_HEAD(&head, n1, entries);
Being this C code (not C++), and C lacks templates, this preprocessor macro can be used to "simulate" templates (note the type parameter).
It's a macro that is used to declare a struct type, with next and prev pointers to instances of a second struct type. That second type can be a parent type, so you can make a "linkable struct" like this:
struct foo {
LIST_ENTRY(foo) list;
int value;
};
This creates a struct foo containing a member called list which in turn is the structure in the question, with the pointers pointing at struct foo.
We can now create a little linked list of struct foos like so:
struct foo fa, fb;
fa.value = 47;
fa.list.le_next = &fb;
fa.list.le_prev = NULL;
fb.value = 11;
fb.list.le_next = NULL;
fb.list.le_prev = &fa.list.le_next;
I'm not 100% sure about the last line, but I think it kind of makes sense.
I am new to C and as a (classic) exercise I am trying to implement some operations on linked lists. I haven't gotten very far yet, though... When I am trying to declare and initialize the root node as follows:
#include <stdlib.h>
struct intNode_t {
int data;
struct intNode_t* next;
};
int main() {
struct intNode_t* root = ( intNode_t* ) malloc( sizeof( struct intNode_t ) );
return 0;
}
the compiler (clang) is giving me the error "use of undeclared identifier" at the place where I am trying to typecast the void pointer returned by malloc to a pointer to intNode_t. I realise this is a noob question, but I couldn't find the answer elsewhere. Any suggestions?
The names of structs in C occupy a separate namespace from the space of names of fundamental types and typedefs (see this question for details). Therefore, the name of your struct type is struct intNode_t; there is no type called intNode_t.
You can either always spell out the name as struct intNode_t, or you can create a type alias for it. There are many different patterns of this in real code:
Separate tag name, separate declaration:
typedef struct foo_t_ foo_t;
struct foo_t_ { /* ... */ };
This allows you to put the type alias in a header and publish it as an opaque API type without ever revealing the actual type definition.
Separate tag name, typedef in struct definition:
typedef struct foo_t_ { /* ... */ } foo_t;
Reuse name:
typedef struct foo_t { /* ... */ } foo_t;
This style allows users to be careless about spelling foo_t or struct foo_t.
Don't name the struct:
typedef struct { /* ... */ } foo_t;
However, in your code you don't actually need to repeat the name, since you should not cast the result of malloc and instead rely on the built-in implicit conversion from void pointer to object pointer. You also shouldn't repeat the type that's already known, and use the expression form of sizeof instead. So you want:
int main()
{
struct intNode_t* root = malloc(sizeof *root);
}
(Also note that return 0 is implied from main.)
No need to repeat yourself. If you don't repeat yourself you can make fewer errors.
struct intNode_t *root;
root = malloc( sizeof *root );
the cast is not needed; malloc() returns a void*, which is exchangeable with every (non-function) pointer type.
there are two syntax variants for sizeof: sizeof(type) and sizeof expression The first one needs (), the second one does not. Most people prefer the second form, because the expression (in your case *root ) always will yield the correct type, and thus: size.
And, the definition + assignment above can be combined into a definition + initialiser, all fitting on one line:
struct intNode_t *root = malloc( sizeof *root );
Name intNode_t was not declared in the program. There is declared structure tag name intNode_t.
So you need to write
struct intNode_t* root = ( struct intNode_t* ) malloc( sizeof( struct intNode_t ) );
Or you could introduce identifier name intNode_t the following way
typedef struct intNode_t {
int data;
struct intNode_t* next;
} intNode_t;
In this case you may write
struct intNode_t* root = ( intNode_t* ) malloc( sizeof( struct intNode_t ) );
I am a beginner in C programming and I know the difference between struct type declaration and typedef struct declaration. I came across to know an answer saying that if we define a struct like:
typedef struct {
some members;
} struct_name;
Then it will be like providing an alias to an anonymous struct (as it is not having a tag name). So it can't be used for forward declaration. I don't know what the forward declaration means.
Also, I wanted to know that for the following code:
typedef struct NAME {
some members;
} struct_alias;
Is there any difference between NAME and struct_alias? Or are both equal as
struct_alias is an alias of struct NAME ?
Furthermore, can we declare a variable of type struct NAME like these:
struct_alias variable1;
and/or like:
struct NAME variable2;
or like:
NAME variable3;
struct forward declarations can be useful when you need to have looping struct declarations. Example:
struct a {
struct b * b_pointer;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
When struct a is declared it doesn't know the specs of struct b yet, but you can forward reference it.
When you typedef an anonymous struct then the compiler won't allow you to use it's name before the typedef.
This is illegal:
struct a {
b * b_pointer;
int c;
};
typedef struct {
struct a * a_pointer;
void * d;
} b;
// struct b was never declared or defined
This though is legal:
struct a {
struct b * b_pointer;
int c;
};
typedef struct b {
struct a * a_pointer;
void * d;
} b;
// struct b is defined and has an alias type called b
So is this:
typedef struct b b;
// the type b referes to a yet undefined type struct b
struct a {
b * struct_b_pointer;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
And this (only in C, illegal in C++):
typedef int b;
struct a {
struct b * struct_b_pointer;
b b_integer_type;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
// struct b and b are two different types all together. Note: this is not allowed in C++
Forward declaration is a promise to define something that you make to a compiler at the point where the definition cannot be made. The compiler can use your word to interpret other declarations that it would not be able to interpret otherwise.
A common example is a struct designed to be a node in a linked list: you need to put a pointer to a node into the struct, but the compiler would not let you do it without either a forward declaration or a tag:
// Forward declaration
struct element;
typedef struct {
int value;
// Use of the forward declaration
struct element *next;
} element; // Complete definition
and so it cant be used for forward declaration
I think that author's point was that giving your struct a tag would be equivalent to a forward declaration:
typedef struct element {
int value;
// No need for a forward declaration here
struct element *next;
} element;
Forward declaration is a declaration preceeding an actual definition, usually for the purpose of being able to reference the declared type when the definition is not available. Of course, not everything may be done with the declared-not-defined structure, but in certain context it is possible to use it. Such type is called incomplete, and there are a number of restrictions on its usage. For example:
struct X; // forward declaration
void f(struct X*) { } // usage of the declared, undefined structure
// void f(struct X) { } // ILLEGAL
// struct X x; // ILLEGAL
// int n =sizeof(struct X); // ILLEGAL
// later, or somewhere else altogether
struct X { /* ... */ };
This can be useful e.g. to break circular dependencies, or cut down the compilation time, as the definitions are usually significantly larger, and so more resources are required to parse it.
In your example, struct NAME and struct_alias are indeed equivalent.
struct_alias variable1;
struct NAME variable2;
are correct;
NAME variable3;
is not, as in C the struct keyword is required.
struct_alias and struct NAME are same ,struct_alias is an alias to struct NAME
These both are same and allowed
struct_alias variable1;
struct NAME variable1;
this is illegal
NAME variable3;
See this article on Forward declaration
As others stated before, a forward declaration in C/C++ is the declaration of something with the actual definition unavailable. Its a declaration telling the compiler "there is a data type ABC".
Lets pretend this is a header for some key/value store my_dict.h :
...
struct my_dict_t;
struct my_dict_t* create();
char* get_value(const struct my_dict_t* dict, const char* name);
char* insert(struct my_dict_t* dict, const char* name, char* value);
void destroy(struct my_dict_t* dict);
...
You dont know anything about my_dict_t, but actually, for using the store
you dont need to know:
#include "my_dict.h"
...
struct my_dict_t* dict = create();
if(0 != insert(dict, "AnEntry", strdup("AValue"))) {
...
}
...
The reason for this is: You are only using POINTERS to the data structure.
POINTERS are just numbers, and for dealing with them you dont need to know what they are pointing at.
This will only matter if you try to actually access them, like
struct my_dict_t* dict = create();
printf("%s\n", dict->value); /* Impossible if only a forward decl is available */
So, for implementing the functions, you require an actual definition of my_struct_t.
You might do this in the source file my_dict.c like so:
#include "my_dict.h"
struct my_dict_t {
char* value;
const char* name;
struct my_dict_t* next;
}
struct my_dict_t* create() {
return calloc(1, sizeof(struct my_dict_t));
}
This is handy for several situations, like
For resolving circular type dependencies, like Sergei L. explained.
For encapsulation, like in the example above.
So the question that remains is: Why cant we just omit the forward declaration at all when using the functions above? In the end, it would suffice for the compiler to know that all dict are pointers.
However, the compiler does perform type checks:
It needs to verify that you don't do something like
...
int i = 12;
char* value = get_value(&i, "MyName");
...
It does not need to know how my_dict_t looks like, but it needs to know that &i is not the type of pointer get_value() expects.
This produces an incompatibility warning:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
int key;
int data;
struct htData_* next;
struct htData_* prev;
}htData_;
typedef struct
{
int num_entries;
struct htData_** entries;
}ht_;
ht_* new_ht(int num_entries);
int ht_add(ht_* ht_p, int key, int data);
int main()
{
int num_entries = 20;
//crate a hash table and corresponding reference
ht_* ht_p = new_ht(num_entries);
//add data to the hash table
int key = 1305;
ht_add(ht_p,key%num_entries,20);
return 0;
}
ht_* new_ht(int num_entries)
{
ht_ *ht_p;
ht_ ht;
ht.num_entries = num_entries;
ht_p = &ht;
//create an array of htData
htData_ *htDataArray;
htDataArray = (htData_*) malloc(num_entries * sizeof(htData_));
//point to the pointer that points to the first element in the array
ht.entries = &htDataArray; // WARNING HERE!!!!!!!!!!!!!!!!
return ht_p;
}
I'm trying to copy the **ptr to the struct containing a **ptr.
Update: My simplified code was not accurate so I've posted the actual code.
The problem is that struct htData_ and htData_ are not the same thing! As far as the compiler is concerned, struct htData_ doesn't exist—it's an incomplete type. htData_, on the other hand, is a typedef for an anonymous structure. For a more detailed analysis, see Difference between struct and typedef struct in C++.
So, you're getting a warning because ht.entries is declared as the type struct htData_**, but the right-hand side of that assignment has type <anonymous struct>**. To fix this, you need to define struct htData_:
typedef struct htData_
{
...
} htData_;
This line is not proper:
htData_ array[20] = htDataArray;
You cannot assign a pointer to an array.
In your edited code, here is the problematic line:
//point to the pointer that points to the first element in the array
ht.entries = &htDataArray;
Actually, syntactically it's correct, so it should not give warning. But you are doing wrong stuff here. If you want ht.entries pointing to the first element of array than you need to declare it as,
htData_* entries; // 'struct' keyword not needed ahead of declaration
and assign it as,
ht.entries = &htDataArray[0];