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.
Related
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.
A little bit of context first. My program features a header, work.h. This header contains a structure, some function definitions, and an extern array of pointers to my base functions.
work.h
typedef struct _foo {
int id;
char something[20];
} foo;
typedef void (*pointer_function)(foo *);
void do_first_to_foo(foo *);
void do_second_to_foo(foo *);
void do_third_to_foo(foo *);
extern pointer_function base_functions[3];
Then a program called work.c with the bodies of the functions, and then the main program main.c. Observe in the header work.h that I have defined prototypes of three functions, and the size of the array is 3, so the pointers on the extern array will point to each one of the 3 functions.
My questions are, how I can associate the pointers of the extern array with the three functions, and second, in which file I need to do it (work.c or main.c).
I understand this association I need to do it in the file work.c, but nothing else.
In work.c:
#include "work.h"
pointer_function base_functions[] = {
do_first_to_foo,
do_second_to_foo,
do_third_to_foo };
Explanation: that array name is a global symbol, and needs to be actually defined in just one compilation unit (.o file produced from .c file). If you do not have it, linker will not find it. If you have multiple copies, linker will complain. You need just one, same as with global exported functions (which are not marked inline).
Edit: Added showing #include "work.h", which is important because it allows compiler to check that extern declaration matches the actual definition. If you leave it out, everything will compile and link without complaints, but you get no indication if there's a mismatch, which could wreak havoc like corrupt other data in memory when variable is used in other compilation units.
New to C. I'm getting the following error when compiling:
error: variably modified 'header' at file scope
error: variably modified 'sequence' at file scope
Code:
struct list{
char header[list_header_size];
char sequence[list_sequence_size];
struct list *next;
};
I thought the error meant that the compiler needed to know what these variables were from the beginning. So, I moved main(), which is where the struct is called, to the end of the program. I also tried declaring the variables at beginning of the program, but I'm not sure if I did that correctly. I tried char header; and char header[];
You are right that the compiler needs to know the types of the members of the struct. One reason why it needs to know the types is so that it can calculate sizes. In your case, however, it can't know the sizes because in your struct you have defined two arrays that are not of a constant size. Therefore, the compiler doesn't know the total size of the struct and this defeats the purpose of knowing the types.
The closest to what you want is to replace the two char arrays with two char pointers and allocate the memory they will point to dynamically.
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.
I've been using the following code to create various struct, but only give people outside of the C file a pointer to it. (Yes, I know that they could potentially mess around with it, so it's not entirely like the private keyword in Java, but that's okay with me).
Anyway, I've been using the following code, and I looked at it today, and I'm really surprised that it's actually working, can anyone explain why this is?
In my C file, I create my struct, but don't give it a tag in the typedef namespace:
struct LABall {
int x;
int y;
int radius;
Vector velocity;
};
And in the H file, I put this:
typedef struct LABall* LABall;
I am obviously using #include "LABall.h" in the c file, but I am NOT using #include "LABall.c" in the header file, as that would defeat the whole purpose of a separate header file. So, why am I able to create a pointer to the LABall* struct in the H file when I haven't actually included it? Does it have something to do with the struct namespace working accross files, even when one file is in no way linked to another?
Thank you.
A common pattern for stuff like that is to have a foo.h file defining the API like
typedef struct _Foo Foo;
Foo *foo_new();
void foo_do_something(Foo *foo);
and a foo.c file providing an implementation for that API like
struct _Foo {
int bar;
};
Foo *foo_new() {
Foo *foo = malloc(sizeof(Foo));
foo->bar = 0;
return foo;
}
void foo_do_something(Foo *foo) {
foo->bar++;
}
This hides all the memory layout and size of the struct in the implementation in foo.c, and the interface exposed via foo.h is completely independent of those internals: A caller.c which only does #include "foo.h" will only have to store a pointer to something, and pointers are always the same size:
#include "foo.h"
void bleh() {
Foo *f = foo_new();
foo_do_something(f);
}
Note: The ISO C standard section on reserved identifiers says that all identifiers beginning with an underscore are reserved. So typedef struct Foo Foo; is actually a better way to name things than typedef struct _Foo Foo;.
Note: I have left freeing the memory as an exercise to the reader. :-)
Of course, this means that the following file broken.c will NOT work:
#include "foo.h"
void broken() {
Foo f;
foo_do_something(&f);
}
as the memory size necessary for actually creating a variable of type Foo is not known in this file.
Since you're asking a precise reason as to "why" the language works this way, I'm assuming you want some precise references. If you find that pedant, just skip the notes...
It works because of two things:
All pointer to structure types have the same representation (note that it's not true of all pointer types, as far as standard C is concerned).[1] Hence, the compiler has enough information to generate proper code for all uses of your pointer-to-struct type.
The tag namespace (struct, enum, union) is indeed compatible accross all translation units.[2] Thus, the two structures (even though one is not completely defined, i.e. it lacks member declarations) are one and the same.
(BTW, #import is non-standard.)
[1] As per n1256 §6.2.5.27:
All pointers to structure types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.
[2] As per n1256 §6.2.7.1:
two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are complete types, then the following additional requirements apply: [does not concern us].
In
typedef struct A* B;
since all pointers' interfaces are the same, knowing that B means a pointer to a struct A contains enough information already. The actual implementation of A is irrelevant (this technique is called "opaque pointer".)
(BTW, better rename one of the LABall's. It's confusing that the same name is used for incompatible types.)