Opaque datatypes and structures in c - c

I have a very simple question.
If I have a source code file like this:
#include<stdio.h>
#include"example.h"
struct mystructure{
//Data Variables
int a;
};
int main(){
mystructure somename;
somename.a = 1;
printf("%d\n", somename.a);
return 0;
}
With a header file like this:
#ifndef EXAMPLE_HEADER_H
#define EXAMPLE_HEADER_H
// Opaque declaration.
struct mystructure;
typedef struct mystructure mystructure;
#endif
The code will compile fine. I could also define the structure in the header file and it will compile fine.
However, if I define the structure in a different source code file and attempt to compile it with the main source code file it will keep throwing errors about forward declarations.
Is there a way to define a structure in a source code file give it a typedef in a header file and use it elsewhere in other source files?
I have been doing this awhile now by defining the structure in the header file, but I would like to know how to do this in a more opaque way.

To perform this declaration and statement
mystructure somename;
somename.a = 1;
the compiler needs to know the complete definition of the structure struct mystructure. For instance it needs to know how much memory to allocate for the object somename and whether the structure has the data member a.
So the definition of the structure must be visible in the module with main where these declaration and statement are present.
To hide the structure definition you could declare a pointer of the type struct mystructure * and call functions to initialize this pointer and data members of the pointed object. The corresponding functions must know the structure definition.

Related

why using typedef in header file and not just do everything in .c

I have a piece of code like this in .c file:
typedef struct stack {
int maxsize;
int top;
int* items;
} stack;
I have read that when using header files, it's better to use this:
.h
typedef struct stack stack;
and do in
.c
struct stack {
int maxsize;
int top;
int* items;
};
My question is that, why can't we use only functions declarations in header files, and the typedef thing, we all do it in the c file? Why the above separation of typedef and struct into different files?
The purpose is private encapsulation, a commonly used best practice during program design. What you describe here is often called "opaque type" since it uses the concept of forward declaration to block the user of your struct to learn or use the contents of the struct. The struct as seen from the header file is an "incomplete type" and the caller can't declare an object of such a type nor access any members inside it.
For details check out How to do private encapsulation in C?
The client (i.e. the code that uses stack) does not need to (and should not) care about the details of what a stack actually is.
If you would put the details into the *.h file, you would need to compile the files that use the struct whenever the definition of the struct changes.
If it's separated, you only need to recompile stack.c and not your entire program.

Problem with C nested structure. error: invalid use of incomplete typedef

For the sake of simplicity I'm going to recreate the actual situation with dummy structures. I have this structure (not my code, I can't edit it):
// private_header_a.h
struct A_s{
int a1;
};
// header_a.h
typedef struct A_s A_t;
Then in one of my headers I extended it this way:
// my_header.h
typedef struct B_s{
A_t* a_f;
int b1;
} B_t;
Now, in my function, I have:
B_t* b;
// Initialization and some other code
b->b1 = 4; // Just an example and compiler does not give any error
// Some other code
b->a_f->a1;
This last line of code makes the compiler throw this error:
error: invalid use of incomplete typedef ‘A_t’ {aka ‘struct A_s’}
Where is the error?
EDIT: the piece of code that triggers the compiler has header_a.h and my_header.h included. private_header_a.h cannot be included directly as not installed (I should copy-paste it, but frankly I would like to avoid to do that)
The compiler error is probably intentional - the library's designers don't want you using A_t directly in that sort of way.
When a struct is only declared in a library's public header file, and only defined in the library's private implementation files, that means you're not supposed to know or care about its members or even size. So looking up that the struct has a member named a1 and writing b->af->a1 is not the intended use. This arrangement is called an "opaque handle". A few of its benefits are that the library keeps your application code from initializing or changing members in ways that don't make sense, and a future version of the library can change the names, numbers, and meanings of the members without breaking your application code.
(Also, how did you get a valid pointer for b->af without doing malloc(sizeof(A_t)) or similar? That sizeof would also cause a compiler error about the incomplete struct type.)
When a library uses an opaque handle, since you can't create any such objects yourself, it will typically provide functions that create the objects for you. Look for public functions in the library with names including init, create, open, etc. which return an A_t* pointer, and read their documentation. Usually there will also be a corresponding destroy, cleanup, close, etc. function which the program should call later when the library object is no longer needed. (In the case of some very simple handles, the function which creates the object might say instead you should just pass the pointer to free. But only do this if the documentation says to!)
Here's two fundamental rules:
Each c file is compiled separately
When you #include a file, think of it as directly replacing the #include line with the contents of the file being included.
Therefore, you are compiling a piece of source code that looks like this:
struct A_s {
int a1;
};
typedef struct B_s {
A_t* a_f;
int b1;
} B_t;
void foo() {
B_t* b;
}
This code doesn't know what A_t is. You've never defined that in the code that's visible to the compiler.
A trivial way to fix this is to replace A_t with struct A_s.

error: storage size of 'name' isn't known

I keep getting this error when compiling. Can someone tell me why this happens?
I have these structs declared in board.c:
struct point {
short int rank;
short int file;
};
struct pieces {
Point pawns[8];
Point Knights[2];
Point BBishop;
Point WBishop;
Point Rooks[2];
Point Queen;
Point King;
};
I also have these typedefs in board.h:
typedef struct point Point;
typedef struct pieces Pieces;
In the main source file (chess.c), I have the declaration:
Pieces White;
When i compile it says:
chess.c: In function 'main':
chess.c:19:10: error: storage size of 'White'isn't known
I tried moving the struct over to board.h, which works just fine. Why wouldn't it work when i have the struct in board.c though?
gcc compiler
When compiling chess.c, it needs to know what the Pieces typedef expands to in order to process a variable declared with that type.
Pointer types can be processed without knowing the full definition of the type it points to, but object types need to know the full definition, because they allocate space for the variable. And to know how much space is needed, the compiler needs to know what the structure members are.
When the compiler is processing chess.c, it only has the information in that source file and any files that it includes. Unless you have #include "board.c" somewhere, the structure definition isn't available while compiling chess.c. It's generally wrong to use #include with .c files, it should normally only be used with .h files. This is why structure definitions and their corresponding typedefs are normally put in the .h file.

Field parent has incomplete type

I'm new to C, and can't get this program to compile. Here's the relevant portion of code:
typedef struct {
git_odb_backend parent;
redisContext *db;
} hiredis_backend;
Compiling results in an error:
error: field 'parent' has incomplete type
Here's the complete file: https://github.com/libgit2/libgit2-backends/blob/master/redis/hiredis.c
Other answers to similar questions mention a header file. Should there be a hiredis.h file as well?
EDIT git_odb_backend is defined here: https://github.com/libgit2/libgit2/blob/development/include/git2/sys/odb_backend.h
I don't know anything about what git_odb_backend is (and neither does the compiler) so here's my advice.
The file hiredis.c needs to know the full declaration of git_odb_backend to allow you to declare it as a non-pointer member variable. This is because the compiler needs to know things about the git_odb_backend such as: What is its size? How do I construct it? It doesn't need to know the function implementations, just what the struct looks like.
So you need to find the header file that declares git_odb_backed and include that in
hiredis.c.
Or, forward declare it and take a pointer:
typedef struct git_odb_backend git_odb_backend;
typedef struct {
git_odb_backend*parent;
redisContext *db;
} hiredis_backend;

How to use pointers to structures

I have defined a structure in one of my source code files. Also I have defined pointer to that structure like (global declaration)
struct blockPropStruct
{ int random_id;
int id;
CvPoint left_up;
CvPoint right_down;
};
typedef struct blockPropStruct *newBlock;
In the same file I am assigning memory to those pointers using malloc to create array of structures.
newBlock = (blockPropStruct*)malloc(maxNum*sizeof(blockPropStruct));
Now I am trying yo use it in some other source file by declaring (global declaration)
extern struct blockPropStruct *newBlock;
Now when I use something like
newBlock[i].left_up.x=mark1[i];
It throws up an error.
It would appear that you have omitted the declaration of the struct type in the file which declares the extern variable.
The name of your structure is struct blockPropStruct. Note that in C, you can't just remove the struct part, it's part of the type's name. You can define a type for your structure so you have less typing, but I think it's better to remember to use your structures as struct blockPropStruct.
Based on the error messages you have added in your comments:
error C2036: 'blockPropStruct *' : unknown size
error C2027: use of undefined type 'blockPropStruct'
You are attempting to get the size sizeof(blockPropStruct) in your malloc() call since blockPropStruct is not a valid identifier so you are attempting to get the size of an undefined type.
To define your type:
typedef struct blockPropStruct blockPropStruct;
Now you can refer to your structure type as blockPropStruct or struct blockPropStruct.
You need to give a name with 'typedef' and point to it.
newBlock = (blockPropStruct*)malloc(maxNum*sizeof(blockPropStruct));
To actually for the above statement to work, the current source file should see the size of structure. So, check whether you have included the corresponding header file.
extern struct blockPropStruct *newBlock;
And when you are doing -
newBlock[i].left_up.x=mark1[i];
You should bring the definition of the blockPropStruct to the current compilation unit to be able to use it members. So, try -
#include "blockPropStruct.h"
extern struct blockPropStruct *newBlock; // This says to use else where
// initialized newBlock
// ....
newBlock[i].left_up.x=mark1[i]; // And to do this, bring the definition
// to this file scope
And there is no need to explicitly typecast malloc.

Resources