Flexible array members in C99

it2022-05-12  56

In a struct with more than one member, the last member of the struct can have incomplete array type. Such a member is called a flexible array member of the struct.

Note

When a struct has a flexible array member, the entire struct itself has incomplete type.

Flexible array members enable you to mimic dynamic type specification in C in the sense that you can defer the specification of the array size to runtime. For example:

 

extern const int n; typedef struct { int len; char p[]; } str;void foo(void) { size_t str_size = sizeof(str); // equivalent to offsetof(str, p) str *s = malloc(str_size + (sizeof(char) * n)); }

Arrays of Length Zero

http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that is really a header for a variable-length object

struct line { int length; char contents[0]; }; int this_length = 10; struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length); thisline->length = this_length;

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.)

GCC versions before 3.0 allowed zero-length arrays to be statically initialized, as if they were flexible arrays. In addition to those cases that were useful, it also allowed initializations in situations that would corrupt later data. Non-empty initialization of zero-length arrays is now treated like any case where there are more initializer elements than the array holds, in that a suitable warning about “excess elements in array” is given, and the excess elements (all of them, in this case) are ignored.

Instead GCC allows static initialization of flexible array members. This is equivalent to defining a new structure containing the original structure followed by an array of sufficient size to contain the data. E.g. in the following, f1 is constructed as if it were declared like f2.

struct f1 { int x; int y[]; } f1 = { 1, { 2, 3, 4 } }; struct f2 { struct f1 f1; int data[3]; } f2 = { { 1 }, { 2, 3, 4 } };

The convenience of this extension is that f1 has the desired type, eliminating the need to consistently refer to f2.f1.

This has symmetry with normal static arrays, in that an array of unknown size is also written with [].

Of course, this extension only makes sense if the extra data comes at the end of a top-level object, as otherwise we would be overwriting data at subsequent offsets. To avoid undue complication and confusion with initialization of deeply nested arrays, we simply disallow any non-empty initialization except when the structure is the top-level object. For example:

struct foo { int x; int y[]; }; struct bar { struct foo z; }; struct foo a = { 1, { 2, 3, 4 } }; // Valid. struct bar b = { { 1, { } } }; // Valid. struct bar c = { { 1, { 2, 3, 4 } } }; // Invalid. struct foo d[1] = { { 1 { 2, 3, 4 } } }; // Invalid.

Arrays of Variable Length

http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html

Variable-length automatic arrays are allowed in ISO C99, and as an extension GCC accepts them in C90 mode and in C++. These arrays are declared like any other automatic arrays, but with a length that is not a constant expression. The storage is allocated at the point of declaration and deallocated when the block scope containing the declaration exits. For example:

FILE * concat_fopen (char *s1, char *s2, char *mode) { char str[strlen (s1) + strlen (s2) + 1]; strcpy (str, s1); strcat (str, s2); return fopen (str, mode); }

Jumping or breaking out of the scope of the array name deallocates the storage. Jumping into the scope is not allowed; you get an error message for it.

You can use the function alloca to get an effect much like variable-length arrays. The function alloca is available in many other C implementations (but not in all). On the other hand, variable-length arrays are more elegant.

There are other differences between these two methods. Space allocated with alloca exists until the containing function returns. The space for a variable-length array is deallocated as soon as the array name's scope ends. (If you use both variable-length arrays andalloca in the same function, deallocation of a variable-length array also deallocates anything more recently allocated with alloca.)

struct entry tester (int len, char data[len][len]) { /* ... */ }

The length of an array is computed once when the storage is allocated and is remembered for the scope of the array in case you access it with sizeof.

If you want to pass the array first and the length afterward, you can use a forward declaration in the parameter list—another GNU extension.

You can also use variable-length arrays as arguments to functions:

struct entry tester (int len; char data[len][len], int len) { /* ... */ }

The ‘int len’ before the semicolon is a parameter forward declaration, and it serves the purpose of making the name len known when the declaration of data is parsed.

You can write any number of such parameter forward declarations in the parameter list. They can be separated by commas or semicolons, but the last one must end with a semicolon, which is followed by the “real” parameter declarations. Each forward declaration must match a “real” declaration in parameter name and data type. ISO C99 does not support parameter forward declarations.

http://www.gidforums.com/t-15161.html

Variable array inside struct

Are you asking about a struct with a "flexible array member" that is part of the C99 standard?From ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16:"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."Such a thing might be used as follows:

#include <stdio.h> #include <stdlib.h> /* a struct with a flexible array member * * Supported by GNU gcc * * Compile with: gcc test_flex.c -Wall -W -pedantic -std=c99 */ typedef struct s_var_ { int size; double p[]; /* Incomplete array type */ } s_var; int main() { int i; /* suppose we want an array of 8 doubles in the struct: */ int siz = 8; s_var *ps; printf("sizeof(int) = %d, sizeof(double) = %d\n", sizeof(int), sizeof(double)); printf("sizeof(s_var) = %d\n\n", sizeof(s_var)); ps = malloc(sizeof(s_var) + siz * sizeof(double)); ps->size = siz; for (i = 0; i < siz; i++) { /* just put something in the array */ ps->p[i] = 1.5 * i; } for (i = 0; i < ps->size; i++) { printf("ps->p[%d] =
转载请注明原文地址: https://win8.8miu.com/read-1493252.html

最新回复(0)