I have a struct that looks like this.
struct MyStruct1 {
int (*fn)();
int b;
}
And another struct that looks like this.
struct MyStruct2 {
int a;
struct MyStruct1 b[0];
}
I would like to declare a global variable of type MyStruct2, somewhat like this.
int func1() { return 1; }
int func2() { return 2; }
struct MyStruct2 a = { 1, { func1, 5 }, { func2, 6 } };
However, I get a "Initializer Element is not a compile-time constant".
I would like to know (a) if it is even possible to globally declare a variable sized struct (or at least define a chunk of space, of the correct size, to have the values inserted into later), and (b) if it is, what am I doing wrong?
It is not possible to declare a variable-size struct, neither locally nor globally. Every type has a fixed size determined at compile time.
The error message you report is surprising, however. If all the declarations you gave are at file scope, in the same file, in the order you gave them, then the initializer for variable a is a compile-time constant. However, it is not a proper initializer for a struct MyStruct2,
because it specifies more elements than that struct type has members,
because the initializer element for a.b is an initializer for a struct MyStruct1 instead of for an array of such, and
because even if you converted the last two initializer elements into one array initializer, it has more elements than there are elements in a.b (i.e. more than zero).
If you want a dynamically-sized array, whether as a variable in its own right or as a member of a struct, then you must declare a pointer to it, and allocate memory for the elements dynamically. In that case, the elements are not themselves part of the struct; only the pointer to them is. (That is different, by the way, from a fixed size array whose size is implicit in its initializer; these are possible only for independent types, though, not for types of struct or union members).
EDIT:
C99 flexible arrays are a possible alternative, as ShafikYaghmour commented. These are similar, but not identical, to a struct element that is a pointer to a dynamically-allocated array. In that case, however, you not only cannot statically declare the array elements, you also cannot statically declare instances of the struct itself, so this wouldn't at all get around your initializer issue. There are several other quirks and limitations. Personally I see few advantages to flexible arrays, but they do make it a bit easier to properly free struct instances.
You cannot create arrays of size 0 in C legitimately. In C99 or C11, you can use a 'flexible array member' like this:
struct MyStruct2 {
int a;
struct MyStruct1 b[];
};
but structures that have a flexible array member can only usefully be created with dynamic memory allocation (other forms of allocation give you an unusable flexible array of size 0).
The older 'struct hack' version of a structure with a variable size array uses an array of size 1 in the structure. You can create global versions of such a structure with an array of size 1.
But basically, you are trying to do what the language prohibits you from doing, and not very surprisingly, you are failing.
What you do about this depends on what you need. Global variables are inherently somewhat undesirable, so there's an element of "you should be trying to avoid doing this". That said, the rules apply to file scope (static) variables too, and those have many uses.
You can use an explicit pointer in place of the array, and have separate allocations of the body of the struct MyStruct2 and its array of struct MyStruct1 members. You can forgo the global variable and use dynamically allocated structures with a flexible array member.
struct MyStruct2 *ms2 = malloc(sizeof(*ms2) + N * sizeof(ms2->b[0]));
This creates an struct MyStruct2 (as shown at the top of this answer) with N members in the array. Without any further changes, you can use ms2->b[0] through ms2->b[N-1] (well, apart from error checking that the malloc() succeeded).
Related
I am new to C programming and in the development of this exercise I encountered this error that I cannot resolve:
Fields must have a constant size: 'variable length array in structure' extension will never be supported
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int nChapters = 2;
typedef struct {
char title[50];
char author[50];
} Heading;
typedef struct {
char title[50];
int number_pages;
} Chapter;
typedef struct {
Heading heading;
Chapter chapters[nChapters]; //Fields must have a constant size: 'variable length array in structure' extension will never be supported
} Book;
printf("\n");
system("read -p 'Press enter to continue...' ");
printf("Hello, World!\n");
return 0;
}
If I replace chapters[nChapters] with an int like chapters[2], program run without problems. Thanks in advance!
In C you have to declare arrays using a fixed length, your nChapters variable is indeed, a variable. You can turn it into a constant variable by simply adding the const keyword:
const int nChapters = 2
You can use the preprocessor directive #define:
#define nChapters 2
The issue is that you are assuming that it is obvious
Chapter chapters[nChapters];
that value of nChapters is 2.
It works that way for a array which is not within a struct or a union.
This is supported by weird, non-standard, non-GCC (but accepted as an extension by GCC in C90 onwards), not recommended feature called as VLA or Variable Length Arrays. Using these, one can allocate a auto class array.
Referring to GNU/GCC documentation, section 6.20, It is trivial to note that,
The storage is allocated at the point of declaration and deallocated when the block scope containing the declaration exits.
C99 recommends a better way to deal with this requirement - by using flexible length array.
§6.7.2.1 Structure and union specifiers
¶18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
So, that would change your struct to:
typedef struct {
Heading heading;
Chapter chapters[];
} Book;
And then allocate the memory dynamically from heap - using malloc.
The size of the array member of the struct has to be a constant expression (skip "flexible member" case and GCC's VLA-in-struct extension).
In the C standard the only portable way to have a true named integer constant is using enums.
Just replace:
int nChapters = 2;
with this:
enum { nChapters = 2 };
Any historical or logical reasons behind it?
Explanation:
when you pass an array to a function in C you actually only pass a pointer to an array.
However, when you pass a struct, you can either pass a copy of the struct or the pointer.
//this:
int function(int array[10])
// is equivalent to this:
int function(int *array)
//and they both pass a pointer
//but this:
int function(struct tag name)
//passes a struct by value, where as this:
int function(struct tag *name)
//passes a pointer to it.
Why the difference?
In the original K&R, you could not pass structs by value. That was a syntax error. Because many compiler vendors offered it as an extension, pass-by-value eventually made its way into the standard.
Why the restriction, and why the evolution? The machines that C was developed on were tiny. Segment sizes of 64 kilobytes were common. Memory was precious, so why copy something when you could just pass the address? Duplicating a 64-byte structure on the stack was an error, probably not even what the user intended.
By the mid-1990s, that wasn't true anymore. 32-bit addressing and RAM of 4 MB or more were common. The restriction was a hinderance and led to some complexity, because without const a structure passed by reference could be modified, perhaps unwittingly.
Why not do the same with arrays? No demand. Arrays and pointers are closely related in C, as you know. The C standard library depends heavily on passing by reference, consider memset and strcpy. Whereas passing a struct by value meant just dropping the & on the call, passing an array by value would have entailed adding new syntax. A compiler vendor that offered, say, by value as C syntax would have been laughed out of the conference.
int function(int array[10]) and int function(int *array) are the same because of 6.7.5.3 Function declarators (including prototypes) (http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf page 118)
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’, where the type qualifiers (if
any) are those specified within the [ and ] of the array type
derivation. If the keyword static also appears within the [ and
] of the array type derivation, then for each call to the
function, the value of the corresponding actual argument shall
provide access to the first element of an array with at least as many
elements as specified by the size expression
.
Of course, you can pass an array by value; all you need to do is wrap it in a struct. But that only works if the array has a definite (and non-variable) size. You can include an indefinitely sized array in a struct, but the resulting type is incomplete and can only be used as the target of a pointer.
That's probably as close as we're going to get to an explanation. The vast majority of arrays passed as arguments are not of fixed size, and passing them by value would not be possible, even if it were intended, which is also unlikely.
There is a similar (but different) decay with functions; a function cannot be passed as an argument, only function pointers. Since it would be tedious to explicitly write & every time you wanted to refer to a function, the language takes care of it for you.
On the whole, questions of the form "Why is this language like this snd not like that?" can only be answered "because that's how it is".
Types are different in both function declarations -
struct tag /* and */ struct tag *
One is structure variable whereas another is pointer to structure.
You can do similar with structures -
int function(struct tag name[]) /*--> int function(struct tag *name) */
These above would be equivalent.
structs are used for declaring own kind of data types with primitive data types like int,float,long(or structs of structs) etc. they are supposed to hold a few of them e.g. struct of students will contain id,name,rollno,subjects,etc. so mostly any struct element will contain 10-20 fields at most (in logical cases), so when you pass a struct to a function, it has to copy 40-100 bytes approx. to make copy of that struct variables. where as arrays can be of huge size and are used to store same kind of information. they can be of size 10^7 in case of integers so if we implement a language to copy whole array for function calls it may have to copy (10^7)*4 bytes which is a huge amount and will impact the performance badly.and typical size of arrays is 10^4 to 10^6 which is still a lot. but if you create struct of array of int(or any other array) you can pass it to a function as a copy of that array. e.g.
#include<stdio.h>
typedef struct {
int arr[10];
}arrayStruct;
void change(arrayStruct a){
a.arr[2]=5;
}
int main(){
arrayStruct a;
for(int i=0;i<10;i++){
a.arr[i]=i;
}
printf("Before:\n");
for(int i=0;i<10;i++){
printf("%d ",a.arr[i]);
}
change(a);
printf("\nAfter:\n");
for(int i=0;i<10;i++){
printf("%d ",a.arr[i]);
}
return 0;
}
this is not done in most of the cases but few times when you need to pass arrays but don't want to alter the contents of them but also require some kind of changes to their copies and want to return that copy you can use this kind of structs of arrays and return them from functions of return type of structs e.g.
arrayStruct returnChange(arrayStruct a){
a.arr[2]=332;
return a;
}
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!
struct test{
unsigned long int asd[][3][6];
};
sizeof(struct test) returns 0. So, if that is an exact alias of
struct test{
unsigned long int asd[0][3][6];
};
is there any practical use for such a field declaration? You may consider also the template metaprogramming stuff, which is always surprising.
The first example demonstrates the use of a flexible array member, a feature of C99. However in order to get that snippet to compile, you need to have another member in your struct, ie:
struct test{
int a;
unsigned long int asd[][3][6];
};
This documentation on gcc tells you why sizeof evaulates to zero, and the syntactical difference of a normal array:
In ISO C90, you would have to give contents a length of 1, which means
either you waste space or complicate the argument to malloc.
In ISO C99, you would use a flexible array member, which is slightly
different in syntax and semantics:
Flexible array members are written as contents[] without the 0.
Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation
of zero-length arrays, sizeof evaluates to zero.
Flexible array members may only appear as the last member of a struct that is otherwise non-empty.
A structure containing a flexible array member, or a union containing such a structure (possibly recursively), may not be a
member of a structure or an element of an array. (However, these uses
are permitted by GCC as extensions.)
It's a "flexible array member", described in section 6.7.2.1 paragraph 16 of the C99 standard (3.7MB PDF).
This is a new feature in C99; some compilers (particularly Microsoft's) might not support it.
Note that a flexible array member must be the last member of a struct, and it cannot be the only member.
It's a replacement for the "struct hack", described in question 2.6 of the comp.lang.c FAQ.
You might want to use undimensioned arrays in systems with custom memory allocators where you have limited ammount of memory. Say, in embedded software.
If you have a struct defined as:
struct test
{
int a;
unsigned long int asd[][6][3];
};
and a memory pool:
int *b = new unsigned long int[1000];
you can 'allocate' memory and use the structure as follows:
test *t;
t = (test*)b;
t->asd[1][2][3] = 1;
This approach is more flexible than making an array of specified dimensions. Of course you can always use a structure like
struct test2
{
int a;
unsigned long int ***asd;
};
but you'll need to initialize the pointer separately and the pointer itself needs 4 bytes.
As a bonus of not using a pointer the structure is represented as a linear memory chunk and can be serialized as is.
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.