How can I resolve this mutual dependency between header files? - c

Please note, there are several questions regarding circular dependencies on SO (including one I have asked myself), but I feel none of them has helped me with this particular problem.
Please consider the two following files:
table.h
#ifndef s_table_h
#define s_table_h
#include "value.h"
#include "object.h"
typedef struct {
ObjectString* key;
Value value;
} Entry;
typedef struct {
int capacity;
int count;
Entry* entries;
} Table;
void initTable(Table* table);
void setTable(Table* table, ObjectString* key, Value value);
bool getTable(Table* table, ObjectString* key, Value* out);
#endif
object.h
#ifndef s_object_h
#define s_object_h
#include "common.h"
#include "table.h"
typedef enum {
OBJECT_STRING
} ObjectType;
typedef struct {
ObjectType type;
Table attributes;
} Object;
typedef struct {
Object base;
char* chars;
int length;
} ObjectString;
bool stringsEqual(ObjectString* a, ObjectString* b);
#endif
As you can see, these two depend on each other: table.h needs ObjectString*, and object.h needs a concrete Table. Both corresponding .c implementation files access concrete members of the ObjectString* and Table respectively.
What is the recommended way to solve this problem? And generally, what would be the common approach to these kinds of problems in C?
Please address purely the technical aspect, and not the software-design one.

I suppose you could argue that I'm addressing the software-design aspect here, but I don't know how to do this without slightly refactoring your code. Namely, by avoiding the typedef temporarily. (Although I would advise dumping the typedef's permanently.) For your particular case, table.h doesn't need to know what ObjectString is, since it only uses a pointer to it. So you can simply not import "object.h" in table.h, and instead write:
object.h:
#ifndef s_object_h
#define s_object_h
#include "common.h"
#include "table.h"
typedef enum {
OBJECT_STRING
} ObjectType;
typedef struct {
ObjectType type;
Table attributes;
} Object;
struct ObjectString {
Object base;
char* chars;
int length;
};
typedef struct ObjectString ObjectString;
bool stringsEqual(ObjectString* a, ObjectString* b);
#endif
table.h:
#ifndef s_table_h
#define s_table_h
#include "value.h"
typedef struct {
struct ObjectString* key;
Value value;
} Entry;
typedef struct {
int capacity;
int count;
Entry* entries;
} Table;
void initTable(Table* table);
void setTable(Table* table, struct ObjectString* key, Value value);
bool getTable(Table* table, struct ObjectString* key, Value* out);
#endif

Maybe you can do like this,put table.h and object.h together to one file named both.h,no longer need table.h and object.h,only use both.h:
#ifndef s_table_h
#define s_table_h
#include "value.h"
#include "common.h"
//#include "object.h"
//#include "table.h"
typedef struct A ObjectString; // add
typedef struct {
ObjectString* key;
Value value;
} Entry;
typedef struct {
int capacity;
int count;
Entry* entries;
} Table;
typedef enum {
OBJECT_STRING
} ObjectType;
typedef struct {
ObjectType type;
Table attributes;
} Object;
typedef struct A { // modify to typedef struct A
Object base;
char* chars;
int length;
} ObjectString;
bool stringsEqual(ObjectString* a, ObjectString* b);
void initTable(Table* table);
void setTable(Table* table, ObjectString* key, Value value);
bool getTable(Table* table, ObjectString* key, Value* out);
#endif

Related

Not sure how to include functions from multiple C files [duplicate]

This question already has an answer here:
How to split a C program into multiple files?
(1 answer)
Closed 28 days ago.
I am not sure what is the best practice for including multiple c files. I was given two header files for an assignment, and am now required to create the corresponding c files.
Right now my issue is that I need to use functions defined in course.c in student.c, however, I am running into a linker issue that I am not sure how to resolve. The way I am currently including files is by creating multiple function definitions!
student.h
#include <stdbool.h>
#include <stdint.h>
struct course;
struct student;
struct student_id {
uint16_t sid_year;
uint32_t sid_serial;
};
struct student* student_create(struct student_id, bool grad_student);
void student_free(struct student*);
void student_take(struct student *s, struct course*, uint8_t grade);
int student_grade(struct student*, struct course*);
double student_passed_average(const struct student*);
bool student_promotable(const struct student*);
student.c
#include "student.h"
#include "course.c"
struct student
{
<Fields>
};
struct student* student_create(struct student_id id, bool grad_student)
{
<definition>
}
void student_free(struct student* s)
{
<definition>
}
void student_take(struct student *s, struct course* c, uint8_t grade)
{
<definition>
}
int student_grade(struct student* s, struct course* c)
{
<definition>
}
double student_passed_average(const struct student* s)
{
<definition>
}
bool student_promotable(const struct student* s)
{
<definition>
}
course.h
#include <stdint.h>
/** Course subjects. */
enum subject {
SUBJ_ENGI,
SUBJ_CIV,
SUBJ_ECE,
SUBJ_MECH,
SUBJ_ONAE,
SUBJ_PROC,
SUBJ_CHEM,
SUBJ_ENGL,
SUBJ_MATH,
SUBJ_PHYS,
};
struct course;
struct course* course_create(enum subject, uint16_t code);
enum subject course_subject(const struct course*);
uint16_t course_code(const struct course*);
void course_hold(struct course*);
void course_release(struct course*);
int course_refcount(const struct course*);
course.c
#include "course.h"
#include <stdio.h>
#include <stdlib.h>
struct course {
<fields>
};
struct course* course_create(enum subject sub, uint16_t code)
{
<definition>
}
enum subject course_subject(const struct course* c)
{
<definition>
}
uint16_t course_code(const struct course* c)
{
<definition>
}
void course_hold(struct course* c)
{
<definition>
}
void course_release(struct course* c)
{
<definition>
}
int course_refcount(const struct course* c)
{
<definition>
}
Which gives the following errors:
gcc *
multiple definition of `course_create'; ... first defined here ...
multiple definition of `course_subject'; ... first defined here ...
multiple definition of `course_code'; ... first defined here ...
multiple definition of `course_hold'; ... first defined here ...
multiple definition of `course_release'; ... first defined here ...
multiple definition of `ref_count'; ... first defined here ...
I am assuming this is an issue with me including course.c in student.c, but I need to include course.c to get the course structure definition. So I am wondering how I can go about retrieving the definition of struct course without using the line #include course.c
Do not #include source files. Move the structure definitions from the source files to the appropriate header files. Use include guards to avoid header files being processed more than once.
Below is a complete example that will compile cleanly with
gcc course.c student.c main.c
This is essentially an application of the answer to How to split a C program into multiple files?, but with functions and structures.
course.h:
#ifndef COURSE_H
#define COURSE_H
#include <stdint.h>
enum subject {
SUBJ_ENGI,
SUBJ_CIV,
SUBJ_ECE,
SUBJ_MECH,
SUBJ_ONAE,
SUBJ_PROC,
SUBJ_CHEM,
SUBJ_ENGL,
SUBJ_MATH,
SUBJ_PHYS,
};
struct course {
enum subject subject;
};
struct course *course_create(enum subject, uint16_t);
enum subject course_subject(const struct course *);
uint16_t course_code(const struct course *);
void course_hold(struct course *);
void course_release(struct course *);
int course_refcount(const struct course *);
#endif
student.h:
#ifndef STUDENT_H
#define STUDENT_H
#include <stdbool.h>
#include <stdint.h>
#include "course.h"
struct student {
char name[128];
};
struct student_id {
uint16_t sid_year;
uint32_t sid_serial;
};
struct student *student_create(struct student_id, bool);
void student_free(struct student *);
void student_take(struct student *, struct course *, uint8_t);
int student_grade(struct student *, struct course *);
double student_passed_average(const struct student *);
bool student_promotable(const struct student *);
#endif
course.c:
#include <stddef.h>
#include <stdint.h>
#include "course.h"
struct course *course_create(enum subject sub, uint16_t code)
{
return NULL;
}
enum subject course_subject(const struct course *c)
{
return SUBJ_ENGI;
}
uint16_t course_code(const struct course *c)
{
return 0;
}
void course_hold(struct course *c)
{
}
void course_release(struct course *c)
{
}
int course_refcount(const struct course *c)
{
return 0;
}
student.c:
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "course.h"
#include "student.h"
struct student *student_create(struct student_id id, bool grad_student)
{
return NULL;
}
void student_free(struct student *s)
{
}
void student_take(struct student *s, struct course *c, uint8_t grade)
{
}
int student_grade(struct student *s, struct course *c)
{
return 0;
}
double student_passed_average(const struct student *s)
{
return 0.0;
}
bool student_promotable(const struct student *s)
{
return false;
}
main.c:
#include <stdio.h>
#include "course.h"
#include "student.h"
int main(void)
{
struct student_id id = { 0, 0 };
struct student *stu = student_create(id, 0);
struct course *cour = course_create(SUBJ_MATH, 0);
puts("Hello world.");
}

How to forward declare a typedef structure in C which has no tag

file1.h: Library code. CANT change it
#ifndef FILE1_H_
#define FILE1_H_
typedef struct
{
int x;
} MY_STRUCT;
#endif /* FILE1_H_ */
file2.h: user defined. can be changed. How to forward declare above typedef struct which has no tag ?
#ifndef FILE2_H_
#define FILE2_H_
struct MY_STRUCT;
void print(struct MY_STRUCT * obj);
#endif /* FILE2_H_ *
file2.c: user defined. can be changed
#include "file2.h"
#include "file1.h"
#include <stdio.h>
void print(struct MY_STRUCT * obj)
{
printf("x: %d", obj->x);
}
main.c
#include "file2.h"
#include "file1.h"
int main(void){
MY_STRUCT obj1;
obj1.x = 100;
print(&obj1);
}
The code can be seen here. https://paiza.io/projects/wa2PCvUswWyyAzdxxjggxQ?language=c
It's not possible to "forward-declare" a typedef . You will have to give the struct a tag, e.g.:
typedef struct my_struct MY_STRUCT;
// ... later
struct my_struct
{
int x;
};

I need someone to explain binary trees for me

edit: found the edit button, fundamental code is at https://github.com/unidef/quantum. it'd be awesome if you clone'd and fixed it, or forked it
here's a quick paste
jons-MacBook-Pro:quantum jon$ cat */*
todo: makefile, srsly
cat: bin/tests: Is a directory
#pragma once
#include "quantum.h"
// tests
TEST temp;
// id system
double long id;
#pragma once
#include "quantum.h"
extern FILE *filename;
extern FILE *extraFileName;
#pragma once
#include "sys.h"
#pragma once
// system macros
#define NEURAL_ARRAY 100
#define NEURAL_DIMENSION 20
#define NEURAL_DIRECTION "up"
#define NEURAL_MALLOC malloc(sizeof(NEURON))
#define NEURAL_MALLOC_BIG malloc(sizeof( NEURON * 20 )
// system libraries
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <math.h>
// built in libraries
#include "types.h"
#include "doc.h"
#include "io.h"
// extra variables
#pragma once
#include "types.h"
typedef struct neural_node NODE;
typedef struct neural OPERATIONS;
typedef struct neural SQL;
typedef struct neural TEST;
typedef struct neural DOC;
typedef struct neural ERROR;
typedef struct neural NEURON;
typedef double long ID;
#pragma once
#include "sys.h"
#include "typedefs.h"
// data structures
struct neural {
ID id;
char *description;
NODE *dimension[NEURAL_ARRAY][NEURAL_ARRAY][NEURAL_ARRAY];
} *N;
struct neural_node {
ID id;
DOC description;
ERROR (*exception)(NODE,DOC); // add SYS
NODE *up;
NODE *down;
NODE *left;
NODE *right;
} *NN;
#include "quantum.h"
// data operations
OPERATIONS arrange();
OPERATIONS delete();
OPERATIONS move();
OPERATIONS rearrange();
OPERATIONS query();
// internal sql database
SQL database();
// used for documentation purposes
DOC license();
DOC help();
void printq(char *msg, DOC *description){
printf(msg, "%s");
}
#include "sys.h"
OPERATIONS arrange();
OPERATIONS delete();
OPERATIONS move();
OPERATIONS rearrange();
OPERATIONS query();
SQL database();
DOC license();
DOC help();
// types
// doc
// system variables
#define NEURAL_ARRAY 1000000
#define NEURAL_DIMENSION 20
#define NEURAL_DIRECTION "up"
// general variables
typedef struct _neural_node NODE;
typedef struct _neural OPERATIONS;
typedef struct _neural SQL;
typedef struct _neural TEST;
typedef struct _neural DOC;
typedef double long ID;
struct _neural {
ID id;
DOC description;
NODE *dimension[NEURAL_ARRAY];
};
struct _neural_node {
ID id;
DOC description;
NODE *up;
NODE *down;
NODE *left;
NODE *right;
NODE dimension[NEURAL_DIMENSION];
};
init:
cc quantum.c -o quantum
tests:
trash:
mv *~ trash
mv lib/*~ trash
mv bin/*~ trash
General Purpose Quantum Paralellization Library
by Unidef
Licensed by the BSD License
#include "lib/quantum.h"
// additional code
int main(){
DOC INIT;
return 0;
};
#include "sys.h"
OPERATIONS arrange();
OPERATIONS delete();
OPERATIONS move();
OPERATIONS rearrange();
OPERATIONS query();
SQL database();
DOC license();
DOC help();
#pragma once
// system libraries
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <math.h>
// built in libraries
#include "types.h"
#include "doc.h"
#include "io.h"
// system variables
#define NEURAL_ARRAY 100
#define NEURAL_DIMENSION 20
#define NEURAL_DIRECTION "up"
#pragma once
#include "types.h"
typedef struct _neural_node NODE;
typedef struct _neural OPERATIONS;
typedef struct _neural SQL;
typedef struct _neural TEST;
typedef struct _neural DOC;
typedef struct _neural ERROR;
typedef struct _neural NEURON;
typedef double long ID;
#pragma once
#include "sys.h"
#include "types.h"
#include "typedefs.h"
// data structures
struct neural {
ID id;
char *description;
NODE *dimension[NEURAL_ARRAY][NEURAL_ARRAY][NEURAL_ARRAY];
};
struct neural_node {
ID id;
DOC description;
ERROR (*exception)(NODE);
NODE *up;
NODE *down;
NODE *left;
NODE *right;
};
jons-MacBook-Pro:quantum jon$
------
sorry for duplicate code, I have a lot of cached files
Basically I have a small database project I want to dub as a neural/ai technology that uses binary trees to high dimensions, I'm just confused on the whole node, pointer, how many pointers to use, etc thing
in my head this is a binary tree.
#define X 100
struct NODE
{
int id;
NODE *movement[X];
};
struct SQL
{
char *description;
NODE *next;
NODE *prev;
NODE *up;
NODE *down;
};
// usage
main()
{
SQL *DOC[X];
DOC[0] = (SQL*)(malloc(sizeof(SQL));
DOC[0]->next->id = 0;
DOC[0]->next->next->id=1;
}
// etc, didn't check it on a compiler
the problem is it segfaults
Is it a requirement to use C or a binary tree? When I was trying to do stuff with neural networks, my approach of multidimensional arrays was to use a flattened array and calculate the index with something like that
double & Tensor::operator[](std::initializer_list<int> list)
{
// TODO: insert return statement here
vector<int> tuple(list.begin(), list.end());
int dim = tuple[0];
int lastDimensions = dimensions[0];
for (int i = 1; i < tuple.size(); i++) {
if (i > dimensions.size() - 1)
{
break;
}
if (tuple[i] > dimensions[i]) throw exception("Dimension do not match");
dim += tuple[i] * lastDimensions;
lastDimensions *= dimensions[i];
}
return elements[dim];
}
(the whole class can be found at Tensor)
but maybe I didn't understand the question correctly...
You defined an array of pointers, not an array of structures. Before using it, you must initialize with pointers to structures of type SQL. Or create an array like SQL DOC [X] = {0};
int main(int argc, char **argv)
{
SQL *ptr = (SQL *) malloc(sizeof(SQL)*X);
SQL DOC[X];
if (!tmp)
return 1;
for (int i = 0; i < X; i++)
DOC[i] = ptr+i;
DOC[0]->next->id = 0;
DOC[0]->next->next->id=1;
}

C - redefinition error in Xcode

My c header file has the following error message in Xcode
Redefinition of 'entry'
But it works perfectly when I compile it using gcc in command line. Could any of you give an explanation of why?
This is snapshot.h:
#ifndef SNAPSHOT_H
#define SNAPSHOT_H
#define MAX_KEY_LENGTH 16
#define MAX_LINE_LENGTH 1024
typedef struct value value;
typedef struct entry entry;
typedef struct snapshot snapshot;
struct value {
value* prev;
value* next;
int value;
};
// the line below is where the redefinition error appears
struct entry {
entry* prev;
entry* next;
value* values;
char key[MAX_KEY_LENGTH];
};
struct snapshot {
snapshot* prev;
snapshot* next;
entry* entries;
int id;
};
#endif
This is snapshot.c:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "snapshot.h"
int
main(int argc, char *argv[]){
int x = 7;
printf("x= %d\n" , x);
printf("value = %d\n", 1);
return 0;
}
entry was originally reserved as a keyword and then later declared obsolete. So older compilers don't allow it (see this question). Change the name of the struct and everything should be fine.

Memory allocation error in C during hashing

I am new to C programming and I was trying to implement typedef and hashing in my code.But I am getting compilation error when I try to allocate memory -
This is my header file
#define MAX1 11
#define MAX2 23
typedef short IP[4];
typedef enum{TRUE = 1,FALSE = 0}boolean;
typedef struct
{
IP p;
char *comp_name;
}Element;
typedef struct
{
Element e;
boolean deleted; // deleted flag
boolean empty;
}Cell;
typedef Cell secLevelHashTable[MAX2];
typedef struct secLevelHashTable *FirstLevelHashTable[MAX1];
typedef struct FirstLevelHashTable hashTable;
This my main code-
#include"hashDef.h"
#include<stdio.h>
#include<stdlib.h>
void initFirstHTable(hashTable H)
{
int i,j;
for(i=0;i<MAX1;i++)
{
H. FirstLevelHashTable[i]=(secLevelHashTable *)malloc(sizeof(secLevelHashTable));
H.FirstLevelHashTable[i]->secLevelHashTable=malloc(sizeof(Cell)*MAX2);
for(j=0;j<MAX2;j++)
{
initSecHTables(H.FirstLevelHashTable[i]->secLevelHashTable[j]);
}
}
}
void initSecHTables(Cell *ptr)
{
ptr->deleted=0;
ptr->empty=1;
}
int main()
{
hashTable h;
h=malloc(sizeof(FirstLevelHashTable));
initFirstHTable(h);
return 0;
}
This is the error I am getting-
In function ‘main’:
hashOps.c:79:13: error: storage size of ‘h’ isn’t known
hashTable h;
Fixed code below. It had numerous small issues and a big one.
Please read the related article the big one:
struct in C: Error storage size of 'params' isn't known -- this will explain "storage size unknown" error; by saying typedef struct FirstLevelHashTable hashTable; you were defining an unfinished struct, rather than referring to existing type.
Header file:
#define MAX1 11
#define MAX2 23
typedef short IP[4];
typedef enum{TRUE = 1,FALSE = 0}boolean;
typedef struct
{
IP p;
char *comp_name;
}Element;
typedef struct
{
Element e;
boolean deleted; // deleted flag
boolean empty;
}Cell;
typedef Cell secLevelHashTable[MAX2];
typedef secLevelHashTable* FirstLevelHashTable[MAX1];
typedef FirstLevelHashTable hashTable;
Main code:
#include"hashDef.h"
#include <stdio.h>
#include <stdlib.h>
void initSecHTables(Cell *ptr)
{
ptr->deleted=0;
ptr->empty=1;
}
void initFirstHTable(hashTable H)
{
int i,j;
for(i=0;i<MAX1;i++)
{
H[i]=(secLevelHashTable *)malloc(sizeof(secLevelHashTable));
for(j=0;j<MAX2;j++)
{
initSecHTables(&((*H[i])[j]));
}
}
}
int main()
{
hashTable h;
initFirstHTable(h);
return 0;
}

Resources