Variably modified 'variable_name' at file scope error? - c

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.

Related

How to define an ADT struct in header file that will be defined in implementation file

I have a header file that declares an ADT modeling a tuple. The header contains a declaration of the struct as typedef struct Tuple * Tuple; The corresponding implementation file defines this as
struct Tuple
{
int x;
int y;
int z;
int w;
};
The problem is that I want to import just the header file in client code (such as a test file or a file containing main). I don't want to include the .c implementation file. Not doing so however results in an error message when attempting code from client code such as:
Tuple tuple = ( Tuple ) calloc( 1, THREE_TUPLE_COORDINATES * sizeof( Tuple ) );
tuple->x ;
that reads as follows: error: dereferencing pointer to incomplete type ‘struct Tuple’
Is it possible leave leave the struct incomplete/undefined in the header and then define it in the implementation file or is this not done/not best practice?
error: dereferencing pointer to incomplete type ‘struct Tuple’
Is it possible leave leave the struct incomplete/undefined in the
header and then define it in the implementation file or is this not
done/not best practice?
You cannot use an abstract / incomplete data type in any context where the actual definition matters. Such contexts include declaring instances, accessing members, and determining the size. How is the compiler supposed to know how much space to reserve? Or where within that space to find the member with a particular name? Or whether such a member even exists?
You can provide functions for most of those things in the same translation unit(s) where the type is defined, and then let other translation units rely on those functions. All instances obtained that way will need to be dynamically allocated, and all member accesses will incur the cost of a function call. This sort of thing is sometimes done, but it's also often not done. Do think carefully about what you want to gain by doing it.

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.

What's the difference between these C external definitions?

I ran into this problem debugging an AVR microcontroller:
I have a main.c file with numerous variable definitions, amongst them an array of structs, like this:
struct mystruct mystruct_array[COUNT];
In another .c file I refer to this array as external, but I left away the array brackets and size so I wouldn't repeat myself and just declared the variable as a pointer (because arrays are essentially pointers, aren't they?):
extern struct mystruct *mystruct_array;
But when I checked the address of the array using printf("%p\n", mystruct_array);I got a null pointer instead of the array's location in memory. Also if I would access the subsequent items in the array, like printf("%p\n", &(mystruct_array[n])); it would print address 0 plus n times sizeof(struct mystruct).
Only after I changed the definition to
extern struct mystruct mystruct_array[COUNT];
(exactly the same as in main.c), I got the true address of the array.
My question: Why does this make a difference to the compiler (in my case avr-gcc)?
That's a fun one.
When you write :
struct mystruct mystruct_array[COUNT];
You create a global array of mystruct structs, there are COUNT of them, and since you didn't initialize it, it'll be filled with zeros.
When you then write:
extern struct mystruct *mystruct_array;
You tell the compiler that there's a variable called mystruct_array somewhere and that it's a pointer. But it's not, it's an array. So the compiler is going to read the content of the array as if it were a pointer.
So when you try to output the value of that pointer, the compiler goes fetch mystruct_array in memory and outputs its content as if it were a pointer. Since it's actually an array full of zeros, you're seeing a null pointer in the output.
Instead you should write something like:
extern struct mystruct mystruct_array[];
So the compiler knows the correct type of your variable. You can specify the length in the square brackets here, but you don't have to.
I'd recommend you go read up on the differences between pointers and arrays to make sure you don't confuse them in the future.
The ideal way to do this is to put an extern declaration in a header file, and a definition in exactly one file. For example,
header.h
extern struct mystruct mystruct_array[];
/* or extern struct mystruct mystruct_array[COUNT] */
main.c
#include "header.h"
#define COUNT 10
/* should have an initializer to be a definition: */
struct mystruct mystruct_array[COUNT] = { 0 };
/* ... */
other.c
#include "header.h"
/* ... */
printf("%p\n", mystruct_array);
That saves you repetition, and limits the places where you might need to make changes. Note that if your header does not define the number of elements in the array, then you cannot apply the sizeof operation to that array in files other than the one that also provides the array definition.
Note, too, that although arrays are not pointers, in most contexts in C source code, an array name is converted to a pointer to the first element of the array. This is the source of the misapprehension that arrays are pointers. Although they are not pointers, in many ways they act as if they were.
The declaration of extern means that the declared object is global in an other C file. Then, when you generate the object file, it is generated also if the declared object (in this case the structure) is not present.
If you declare:
extern struct structname * s;
means that in the other C module there's a global visible pointer to a structure structname s.
If you declare:
extern struct structname s;
means that in the other C module there's a global visible structure structname s!
When you will link the program, if you don't indicate to the linker to link the object that contains the structure, you will get an Undefined reference!

typedef stuct with forward declaration in C

I have something like:
typedef struct Data DATA, *DATA_PTR;
typedef struct Units UNITS, *UNITS_PTR;
struct Data
{
double miscData;
UNITS units;
};
struct Units
{
double x[2];
double y[2];
double z[2];
};
in my project_typedef.h file.
In another file, I have something like:
void fileInput(DATA_PTR data)
{
//usual declarations and other things
data->miscData = 0; //Works!
data->units.x[0] = 5; //Doesn't work
//etc...
}
However, this doesn't work since units is declared after data in project_typedef.h (if I switch the order it works). The error that i get is "left of '.x' must have struct/union type". I thought that the forward declaration would fix this issue. Why not?
When you define Data, all members must be complete types. Since UNITS isn't a complete type at that point, this doesn't work. (By contrast, UNITS_PTR would be fine, since pointers to incomplete types are complete types.)
Simply put the Units definition above the Data definition and you should be fine.
(As #cnicutar already noted, you're also using the array x wrong.)
The forward declaration allows you to use its name in context where an incomplete type is allowed. Declaring a struct member is not one of such cases, the complete definition must be known as it contributes to the struct layout.
for a struct definition you should always use complete types for all members in a structure... but this is not the case with UNITS units in struct Data,which declares a variable named units of type struct Units which is never declared before the struct Data... this reflects an error.. you should place the Units definition above Data definition.. and all will work fine..
and regarding forward declaration this does not work since whenever a struct variable is defined, the compiler first allocates the memory required to the struct (struct members donot have a memory allocated to them, unless they are linked to a struct type of variable.. thats why struct variables cant be initialized inside struct template).. :)
There is no prototype for struct. This is because compiler needs to know size of struct before using it. You could use pointer on struct, because pointers have known size no matter which type they point to.

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