Can you modify a typedef in a different header file - c

I'm working on some data structures in C. I have created a queue data structure that can take any type of data. This is currently being done by a macro which is default initialized to int type.
#ifndef DATATYPE
#define DATATYPE int
#endif
The queue header is being included in another data structure - the binary search tree, and I am using the queue for a breadth-first-search implementation. In the Makefile, I have modified the DATATYPE macro from an int to a binary_tree_node_t * type.
binary_tree: DEFS=-DDATATYPE="struct BINARY_TREE_NODE *"
My question is, is there a better way to do this using typedefs? Can I define a type DATATYPE as an int in the queue implementation, but have it get modified in a different header file?
Or is it possible to implement a queue that can take any datatype?
Here are the source files (redacted for sake of brevity) for reference:
queue.h
#ifndef _QUEUE_H
#define _QUEUE_H
#ifndef DATATYPE
#define DATATYPE int
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef struct LL_NODE {
DATATYPE data;
struct LL_NODE* next;
} node_t;
typedef struct QUEUE {
node_t* head;
node_t* tail;
int size;
} queue_t;
queue_t* init_queue();
void destroy(queue_t* queue);
bool is_empty(queue_t* queue);
int size(queue_t* queue);
void enqueue(queue_t* queue, DATATYPE data);
DATATYPE dequeue(queue_t* queue);
DATATYPE peek(queue_t* queue);
#endif
binary_search_tree.c
#include "binary_search_tree.h"
void bfs_trav(binary_tree_node_t* root) {
queue_t* queue = init_queue();
binary_tree_node_t* temp = root;
enqueue(queue, root);
while (!is_empty(queue)) {
temp = dequeue(queue);
printf("%d ", temp->data);
if (temp->left) {
enqueue(queue, temp->left);
}
if (temp->right) {
enqueue(queue, temp->right);
}
}
destroy(queue);
return;
}
binary_search_tree.h
#ifndef _BINARY_SEARCH_TREE_H
#define _BINARY_SEARCH_TREE_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "../queue/queue.h"
typedef struct BINARY_TREE_NODE {
int data;
struct BINARY_TREE_NODE *left;
struct BINARY_TREE_NODE *right;
} binary_tree_node_t;
void bfs_trav(binary_tree_node_t* root);
#endif

One popular way to do what you're trying to do is to nest your data structures and thereby make "polymorphic" types. In your case, that would mean removing the payload from the LL_NODE struct entirely and declare various "derived" structs as needed. For example:
typedef struct LL_NODE {
struct LL_NODE* next;
} node_t;
typedef struct INT_NODE {
node_t node;
int payload;
} int_node_t;
typedef struct TREE_NODE {
node_t node;
struct BINARY_TREE_NODE *payload;
} tree_node_t;
Any time you want to work with the linked list simply pass a pointer to the node struct member for any derived type.
Of course for this to be useful, you'll need a way to "downcast" from a linked list node to a derived type. This is usually done with a macro that will look roughly as follows:
#define LIST_NODE_DOWNCAST(ptr, derivedType, nodeName) \
(derivedType *)((ptrdiff_t)ptr - (ptrdiff_t)&((derivedType *)0)->nodeName)
So for example, given a node_t pointer called list_ptr, that you know refers to an int_node_t object, you can recover the int_node_t object as follows:
int_node_t *derived = LIST_NODE_DOWNCAST(list_ptr, int_node_t, node);
Note that this is the primary method used in the Linux kernel for managing queues and lists. I answered a related question a while ago where you can see a specific example in usage in the kernel.

I would suggest (quite strongly) that the makefile is the wrong place to make that change. You should be setting the data type in the BST code before including queue.h:
…
#define DATATYPE struct BINARY_TREE_NODE *
#include "queue/queue.h"
…
Your binary tree code knows what it wants to use; it should not rely on the vagaries of the makefile to ensure it gets what it needs.
Whether you should add #undef DATATYPE before defining it is trickier; I'd not do it unless it was proven necessary — and I'd also debate why it's necessary and how you are going to have two sets of functions with the same names but working with different types, given that this is C and C++. On the whole, not using #undef is safer; you will be told if there is a problem which using #undef will conceal — and the concealed problems will be hell to debug!

Related

Usage of Typedef Struct in C programming

I have a C template which is given me as homework. But before doing homework, I need to understand the usage of "typedef" and "struct" clearly to move on coding. Here is the code;
typedef struct NODE_s *NODE;
typedef struct NODE_s
{
NODE right;
NODE left;
unsigned long data;
int height;
} NODE_t[1];
typedef struct TREE_s *TREE;
typedef struct TREE_s
{
NODE root;
} TREE_t[1];
TREE tree_init();
NODE node_init(unsigned long data);
First of all, what is the line typedef struct NODE_s *NODE; is doing here? Why it is named like a pointer with a *?
Then, after the struct definition, what is the purpose of creating a variable named NODE_t[1], is the square brackets with the number "1" something connected with an array, or it is just something else?
Lastly, when the tree_init(); and node_init(unsigned long data); functions are declared, why the TREE and NODE datatype names are used to the contrary they were declared as *TREE and *NODE before the struct definitions? Thank you for the answers.
The template you were given is this, where I've added numbers to some of the lines for ease of reference:
typedef struct NODE_s *NODE; // 1
typedef struct NODE_s // 2
{
NODE right; // 3
NODE left;
unsigned long data;
int height;
} NODE_t[1]; // 4
typedef struct TREE_s *TREE;
typedef struct TREE_s
{
NODE root;
} TREE_t[1];
TREE tree_init(); // 5
NODE node_init(unsigned long data);
What are the problems here?
As noted in comments, the SO Q&A Is it a good idea to typedef pointers suggests that it is not a good idea to typedef pointers, with limited exceptions for 'pointers to functions' (not relevant here) and perhaps (but probably not) for opaque types. This line does two things: (1) it says "there is a structure type with the tag NODE_s; (2) the name NODE is a synonym for struct NODE_s *. The structure type is incomplete at the moment; no details are known about its members.
This line starts a new typedef, but also starts the definition of the type struct NODE_s (because of the { that follows on the next line).
The type NODE is already known; it can be used here. It means the same as if you wrote struct NODE_s *right;.
The name NODE_t is an alias for the type struct NODE_s[1], an array of 1 struct NODE_s. It isn't clear what this is going to be used for. I have reservations (at best) about its existence. (You can also apply the discussion in points 1, 2, 4 to the struct TREE_s type, mutatis mutandis.)
This is a function declaration, but it is not a prototype declaration. It says that the tree_init() function can be called with any number of arguments of any type because no information is specified about the number or type of those arguments. We do know it is not a variadic function (variable argument list, like printf()) because those must have a full prototype declaration ending with , ...) in scope before they're used. If you want to specify that the function takes no arguments, say so: TREE tree_init(void);.
I think the intent behind the NODE_t and TREE_t types is to allow you to write, for example:
int main(void)
{
TREE_t x = { 0 };
if (x->root != 0)
return 1;
return 0;
}
I'm not convinced whether that's sufficiently helpful to warrant the type compared with using struct NODE_s x and using x.root in the test. It does save you from having to add an & when passing a pointer to a function; again, I'm not sure it is really sufficiently helpful to warrant its existence.
What I would prefer to see as the template is:
typedef struct NODE_s NODE;
struct NODE_s
{
NODE *right;
NODE *left;
unsigned long data;
int height;
};
typedef struct TREE_s TREE;
struct TREE_s
{
NODE *root;
};
extern TREE *tree_init(void);
extern NODE *node_init(unsigned long data);
This removes the pointers from the typedef statements, avoids the somewhat peculiar array types, and uses an explicit prototype for tree_init(). I personally prefer to have function declarations marked with extern; in a header, they'll match the extern on those rare global variables that are declared in the header. Many people prefer not to use extern because the compiler assumes that anyway — so be it; the most important thing is consistency.
The code in main() would now be written:
int main(void)
{
TREE x = { 0 };
if (x.root != 0)
return 1;
return 0;
}
The difference? An arrow -> changed to a dot .. Not a lot of problem there. However, when calling functions, you'd probably use &x whereas with the TREE_t type, you would just write x (because it's an array).

Generic data structure search in c

I'm trying to code a fully generic data structure library in c.
Is there any way or technique in c programming that allows searching data without knowing its type?
Here I have to define my compare function again upon my data type.
list.h
typedef struct _node
{
void *data;
struct _node *next;
}NODE;
typedef struct _list
{
NODE *head;
NODE *tail;
NODE *current;
}GLIST;
int search(GLIST *list,void *data,int (*COMPARE)(void*,void*));
and
list.c
int search(GLIST *list,void *data,int(*COMPARE)(void*,void*))
{
list->current=list->head;
int cIndex=1;
while(list->current)
{
if(COMPARE(list->current->data,data))
{
printf("data found at position %i.\n",cIndex);
if(list->current->next==NULL)
{
return 1;
}
}
list->current=list->current->next;
cIndex++;
}
printf("NO DATA FOUND.\n");
return 0;
}
and
mycode.c
int compare(void *list,void *data);
typedef struct _student
{
int studentNumber;
char name[64];
}STUDENT;
int main()
{
GLIST list;
//initializing list......
STUDENT stud;
//code .....
search(&list,&stud,compare) // I want an alternative of using compare here
search(&list,&stud); // want the function be like this and also be generic !
return 0;
}
int compare(void *list,void *data)
{
// I do not wanna have to declare this function even
return !strcmp(((STUDENT*)list)->name,((STUDENT*)data)->name);
}
I'm wondering if there is A COMMON thing to compare elements "structures,unions,arrays" upon it in c or any technique else.
There is no way of comparing two objects without knowing their data type.
A first attempt would probably be to use something like memcmp, but this fails for at least three reasons:
Without knowing the type, you do not know the size of the object.
Even if you somehow could derive some size, comparing objects of type struct or union could lead to wrong result due to padding.
A comparison based on the memory layout could at most achieve a "shallow" comparison, which may not represent "equality" in terms of the respective data type.
So the only way (and this is used by generic libraries) is to define functions that accept user-defined comparison functions as parameters.

Storing and using type information in C

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.

Calling a node from another file

I know that in programming it is important to keep things simple and be able to be changed. So to me that means it is important to use different files and functions and to keep them separate to easier isolate faults and improve readability.
I am new to C and I don't understand how to do this. I have my nodeTest.h
#include <stdio.h>
#include <stdlib.h>
struct nodeTest
{
int data;
struct nodeTest* next;
};
Then I have another file trying to call that struct
#include <stdio.h>
#include <stdlib.h>
#include "nodeTest.h"
nodeTest* first = (nodeTest*)malloc(sizeof(nodeTest));
I am getting an error saying that nodeTest is undeclared(not in function). What does that mean and why can I not use include to include a struct or typedef?
You have to use struct NodeTest instead of NodeTest.
Thats because C differentiates three namespaces:
Namespace of structs.
Namespace of type aliases (type names).
Namespace of enums and unions.
So everywhere you want to use an struct, you have to specify the compiler that name refers to an struct. For example:
int main()
{
struct NodeTest node;
}
One workaround to that problem is to specify an alias to that struct, to "add" the struct to the types namespace:
typedef NodeTest NodeTestType;
int main()
{
NodeTestType node; //OK
}
Or using the common idiom, declare directly the struct as an alias:
typedef struct { ... } NodeTest;
Note that what this sentence does is to make an alias named NodeTest to an unnamed struct
you have declared in the same instruction.
One problem of this approach is that you cannot use the type inside the struct, because its not declared yet. You could workaround it naming the struct:
typedef struct nodeTest //<-- Note that the struct is not anonimous
{
int data;
struct nodeTest* next;
} nodeTest;
Within global scope, you can just declare / define functions, structures or global variables. You can not call a function just like that (literally "out of nowhere"). Create a mainand call malloc from within:
int main(void) {
nodeTest* first = (nodeTest*) malloc(sizeof(nodeTest));
free(first);
return 0;
}
struct nodeTest {
int data;
struct nodeTest* next;
};
defines struct nodeTest so
nodeTest* first;
is unknown to compiler. To solve this you could either use:
struct nodeTest* first;
or even better: use typedef while defining your struct and everything will be fine:
typedef struct nodeTest {
int data;
struct nodeTest* next;
} nodeTest ;
you need to define nodetest type
typedef struct nodeTest_t
{
int data;
struct nodeTest_t* next;
}nodeTest;
or else
in main(), use struct keyword before nodeTest.
Just put your code inside a function like this:
#include <stdio.h>
#include <stdlib.h>
#include "nodeTest.h"
int main(void) {
struct nodeTest* first = malloc(sizeof(struct nodeTest));
return 0;
}

malloc undefined

I am currently working on rewriting a linked list module and I am receiving some weird errors.
In two IDEs (Netbeans & Visual Studio Express), I am getting a warning that malloc is undefined and that a function found in my linkedlist.c file is not defined either.
below are my 3 files.
main.c
#include <stdlib.h>
#include <stdio.h>
#include "linkedlist.h"
int main(void){
struct linked_list * l_list;
l_list = new_list();
printf("%i", l_list->length);
getchar();
return (EXIT_SUCCESS);
}
linkedlist.h
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
struct linked_list{
int length;
struct linked_list_node * head_node_ptr;
};
struct linked_list_node{
struct linked_list_node * prev_node_ptr;
struct linked_list_node * next_node_ptr;
struct linked_list_data * head_data_ptr;
};
struct linked_list_data{
struct linked_list_data * prev_data_ptr;
struct linked_list_data * next_data_ptr;
void * data;
};
struct linked_list * new_list();
#endif
linkedlist.c
#include "linkedlist.h"
struct linked_list * new_list(){
struct linked_list * temp_list = malloc(sizeof(struct linked_list));
temp_list->length = 5;
return temp_list;
}
Any help would be greatly appreciated. I am unsure if this is a syntax issue or missing files on my computer.
Where do you include <stdlib.h> — because that is where malloc() is declared?
Is this a compilation problem (malloc() undeclared) or a linking problem (malloc() undefined)?
What exactly is the error message?
Now the code is readable:
<cstdlib> is a C++ header (so is <cstdio>).
You need to include <stdlib.h> in C.
You need to include <stdlib.h> where the malloc() function is used — in linkedlist.c.
You also have had the header guards in the wrong place in linkedlist.h, but the code in the question has been updated since. Originally, the sequence was:
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#endif
struct linked_list{
…
The canonical structure for a header file is:
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
...the other material in the header...
...definitions and declarations...
#endif /* HEADER_H_INCLUDED */
The #endif is the last non-comment, non-blank line in the file — not the third.
Your data structures are extraordinarily complicated for even a doubly-linked list. Are you sure you're going to be needing the length so often that it warrants maintaining the pointer to the head in every node in the list? I'd be surprised if you are using it that often. I assume that you have the pointer-to-head in each node so that when you remove an arbitrary node from the list you can decrement the length of the list. You'd probably be better off passing a pointer to the list and the pointer to the node to be deleted than what you've got.
I can see no justification for the length = 5 in the new_list() function.
Also, C and C++ differ radically on the meaning of:
struct linked_list * new_list();
In C++, that means "new_list() is a function that takes no arguments and returns a struct linked_list pointer".
In C, that means "new_list() is a function with a completely indeterminate argument list that returns a struct linked_list pointer". The function is declared, but there is no prototype for the function.
In C, you should write:
struct linked_list * new_list(void);
Personally, I prefer to see extern in front of function declarations in headers; it is not actually necessary for functions, but since it (extern) is (or should be) necessary for variables declared in headers, I prefer the symmetry for functions declared in headers.
From your question, it appears you are on a Windows machine. You may have to do:
#include <windows.h>
in order to have malloc() available.
cstdlib and cstdio are not standard C headers. Perhaps you meant stdlib.h and stdio.h.
you must use malloc() like below:
for (int i = 2; i < 10; i++){
item *temp = (item*)malloc(sizeof(item));
temp->data = i;
pre->next = temp;
pre = temp;
}

Resources