In fact, I saw this in LINUX as early as I saw it. Later I also saw something similar in the MFC memory pool. I also wrote a similar small memory pool according to MFC, (MFC uses return this + 1) later, I saw a similar definition in Li xianjing's System Programmer growth plan, So I thought about it as a summary, the results showed that some cool people on the Internet had already summarized it very well, so it turned around. Thank you for your sharing. This is my motivation for moving forward!
At the same time, it should be noted that such writing in ISO/IEC 9899-1999 is illegal. This is only an extension of gnu c, and gcc can allow the existence of this syntax phenomenon. However, I have not tested the latest C/C ++. (C99 is allowed. The VS series of Microsoft reports a WARNING, which is a very standard extension .)
The final reason for the struct to use an array of 0 or 1 is mainly to facilitate memory buffer management. If you directly use a pointer instead of an array, then when you allocate a memory buffer, you must allocate the struct once, and then assign the pointer to the body once. (at this time, the allocated memory is not sequential with the struct memory, so you must manage it separately to apply for and release it) if an array is used, all resources can be allocated once (see the example below). In turn, the release is the same. The array is used, the release is performed once, And the pointer is used, first release the pointer in the structure body and then release the structure. The order cannot be reversed.
In fact, it is to allocate a continuous memory to reduce memory fragmentation.
The final length of the title struct is 0 or 1. Select the Blog from googol4u.
In Linux,/usr/include/linux/if_pppox.h has the following structure:
Struct pppoe_tag {
_ 2010tag_type;
_ 16tag_len;
Char tag_data [0];
} _ Attribute (packed ));
The last member is an array of variable Length. for a structure in the form of TLV (Type-Length-Value) or other struct requiring variable Length, it is best to define it in this way. It is very convenient to use. When you create a malloc segment, the size of the structure and the space of the variable length data are given to it. The variable length part can be accessed by array, you can directly free the entire struct. Example:
Struct pppoe_tag * sample_tag;
_ 2010sample_tag_len = 10;
Sample_tag = (struct pppoe_tag *) malloc (sizeof (struct pppoe_tag) + sizeof (char) * sample_tag_len );
Sample_tag-> tag_type = 0 xffff;
Sample_tag-> tag_len = sample_tag_len;
Sample_tag-> tag_data [0] = ....
...
When released,
Free (sample_tag)
Can I use char * tag_data instead? In fact, it is very different from char * tag_data. To illustrate this problem, I wrote the following program: www.2cto.com
Example 1: test_size.c
10 struct tag1
20 {
30 int;
40 int B;
50 }__ attribute (packed ));
60
70 struct tag2
80 {
90 int;
100 int B;
110 char * c;
120 }__ attribute (packed ));
130
140 struct tag3
150 {
160 int;
170 int B;
180 char c [0];
190 }__ attribute (packed ));
200
210 struct tag4
220 {
230 int;
240 int B;
250 char c [1];
260 }__ attribute (packed ));
270
280 int main ()
290 {
300 struct tag2 l_tag2;
310 struct tag3 roletag 3;
320 struct tag4 l_tag4;
330
340 memset (& l_tag2, 0, sizeof (struct tag2 ));
350 memset (& l_tag3, 0, sizeof (struct tag3 ));
360 memset (& l_tag4, 0, sizeof (struct tag4 ));
370
380 printf ("size of tag1 = % d \ n", sizeof (struct tag1 ));
390 printf ("size of tag2 = % d \ n", sizeof (struct tag2 ));
400 printf ("size of tag3 = % d \ n", sizeof (struct tag3 ));
410
420 printf ("l_tag2 = % p, & l_tag2.c = % p, l_tag2.c = % p \ n", & l_tag2, & l_tag2.c, l_tag2.c );
430 printf ("l_tag3 = % p, l_tag3.c = % p \ n", & l_tag3, l_tag3.c );
440 printf ("l_tag4 = % p, l_tag4.c = % p \ n", & l_tag4, l_tag4.c );
450 exit (0 );
460}
_ Attribute (packed) is used to force 4-byte alignment, which is easy to illustrate.
The program running result is as follows:
Size of tag1 = 8
Size of tag2 = 12
Size of tag3 = 8
Size of tag4 = 9
Rochelle tag2 = 0xbffffad0, & Rochelle tag2.c = 0xbffffad8, Rochelle tag2.c = (nil)
L_tag3 = 0xbffffac8, l_tag3.c = 0xbffffad0
Rochelle tag4 = 0 xbffffabc, Rochelle tag4.c = 0xbffffac4
From the above program and running results, we can see that tag1 itself contains two 32-bit integers, so it occupies 8 bytes of space. Tag2 contains two 32-bit integers plus a char * pointer, so it occupies 12 bytes. Tag3 is the difference between char c [0] and char * c. c In char c [0] is not a pointer but an offset, this offset points to the space next to a and B, so it does not actually occupy any space. Tag4 adds this point. Therefore, if the last member of the struct pppoe_tag above is defined using char * tag_data, it will not be used unless it occupies four more byte pointer variables:
Method 1: during creation, you can first allocate a memory for struct pppoe_tag and then allocate the memory for tag_data. In this way, you must first release the memory occupied by tag_data and then release the memory occupied by pppoe_tag;
Method 2: During the creation, a piece of struct pppoe_tag size and the tag_data memory are directly allocated to the struct pppoe_tag. From Row 1 of Example 1, we can see that the content of tag_data needs to be initialized, point tag_data to the memory behind the strct pppoe_tag.
Struct pppoe_tag {
_ 2010tag_type;
_ 16tag_len;
Char * tag_data;
} _ Attribute (packed ));
Struct pppoe_tag * sample_tag;
_ 2010sample_tag_len = 10;
Method 1:
Sample_tag = (struct pppoe_tag *) malloc (sizeof (struct pppoe_tag ));
Sample_tag-> tag_len = sample_tag_len;
Sample_tag-> tag_data = http://www.cnblogs.com/winkyao/archive/2012/02/14/malloc (sizeof (char) * sample_tag_len );
Sample_tag-> tag_data [0] =...
Release:
Free (sample_tag-> tag_data );
Free (sample_tag );
Method 2:
Sample_tag = (struct pppoe_tag *) malloc (sizeof (struct pppoe_tag) + sizeof (char) * sample_tag_len );
Sample_tag-> tag_len = sample_tag_len;
Sample_tag> tag_data = http://www.cnblogs.com/winkyao/archive/2012/02/14/ (char *) sample_tag) + sizeof (struct pppoe_tag );
Sample_tag-> tag_data [0] =...
Release:
Free (sample_tag );
Therefore, no matter which method is used, it is convenient to define char tag_data [0.
After talking about this, it actually involves the difference between arrays and pointers in a C language (that is, the memory management problem we mentioned, arrays are allocated with contiguous spaces after the struct space address, while pointers are allocated in a random space segment ). Is a in char a [1] the same as B in char * B? "Arr is defined to be identical to & arr [0]", said on page 82 of Programming into actions in C (Berts, E. S., Mechanical Industry Press, 2004.6). That is to say, a in char a [1] is actually a constant, which is equal to & a [0]. Char * B has a real pointer variable B. Therefore, a = B is not allowed, and B = a is allowed. Both variables support subscript access. Is there any difference between a [0] and B [0] in essence? An example is provided.
Example 2:
10 # include <stdio. h>
20 # include <stdlib. h>
30
40 int main ()
50 {
60 char a [10];
70 char * B;
80
90 a [2] = 0xfe;
100 B [2] = 0xfe;
110 exit (0 );
120}
After compilation, you can use objdump to view its assembly:
080483f0 <main>:
80483f0: 55 push % ebp
80483f1: 89 e5 mov % esp, % ebp
80483f3: 83 ec 18 sub $0x18, % esp
80483f6: c6 45 f6 fe movb $ 0xfe, 0xfffffff6 (% ebp)
80483fa: 8b 45 f0 mov 0xfffffff0 (% ebp), % eax
80483fd: 83 c0 02 add $0x2, % eax
8048400: c6 00 fe movb $ 0xfe, (% eax)
8048403: 83 c4 f4 add $0xfffffff4, % esp
8048406: 6a 00 push $0x0
8048408: e8 f3 fe ff call 8048300 <_ init + 0x68>
804840d: 83 c4 10 add $0x10, % esp
8048410: c9 leave
8048411: c3 ret
8048412: 8d b4 26 00 00 00 00 lea 0x0 (% esi, 1), % esi
8048419: 8d bc 27 00 00 00 00 lea 0x0 (% edi, 1), % edi
It can be seen that a [2] = 0xfe is a direct addressing, and 0xfe is directly written into the address of & a [0] + 2, while B [2] = 0xfe is an indirect addressing, take out the content (address) of B, add 2, and then write 0xfe into the calculated address. Therefore, a [0] and B [0] are essentially different.
However, when an array is used as a parameter, it is no different from a pointer.
Int do1 (char a [], int len );
Int do2 (char * a, int len );
There is no difference between the two functions. Are actually existing pointer variables.
By the way, the last member of struct pppoe_tag is defined as char tag_data [0]. Some compilers do not support the definition of arrays with a length of 0. In this case, it can only be defined as char tag_data [1]. The usage is the same.
In the source code of openoffice, we can see the following data structure, which is a unicode String Structure. Its final length is an array of 1, which may be compatible or cross-compiler.
Typedef struct _ rtl_uString
{
Sal_Int32 refCount;
Sal_Int32 length;
Sal_Unicode buffer [1];
} Rtl_uString;
This is an indefinite string. The general meaning is as follows:
Rtl_uString * str = malloc (256 );
Str-> length = 256;
Str-> buffer now points to a buffer with a length of 256-8.
Conclusion: The reposted article above clearly shows that the advantage of this method is to simplify memory management. We assume that in the ideal memory state, the allocated memory space can be sorted in order (of course, the actual memory fragmentation may vary) we can use the pointer of the last array to directly jump to the allocated Array Buffer without any interval. This is very common in LINUX. in WINDOWS, I have seen similar in MFC, in other cases, I cannot remember clearly. I only remember that in MFC, we can use the pointer of the allocated struct (this) to directly + 1 (for detailed methods, please refer to my blog: in the CE classification: the application and detailed description of the memory pool technology), it jumps to the actual memory space, also thought for a long time, so many things seem very complicated, in fact, they are all basic things, so we must lay a solid foundation. This is the prerequisite and guarantee for the high-rise buildings, and the same is true for learning. We should never go too far. We should be down-to-earth and step by step, in addition, we need to summarize our experiences and experiences from time to time, and constantly validate our theories and practices so that we can go further and see more beautiful scenery.
Finally, I would like to thank the kids shoes that we have shared online !!!
Flexible array structure members
In C99, the last element in the structure can be an array of unknown size, which is called a flexible array member, but the flexible array member in the structure must be at least one other member. Flexible array Members allow the structure to contain an array of variable sizes. The size of the structure returned by sizeof does not include the memory of the flexible array. The structure containing flexible array members uses the malloc () function to dynamically allocate memory, and the allocated memory should be larger than the size of the structure to adapt to the expected size of the flexible array .]
C language Daquan, "flexible array members"
Flexible array structure member
In C99, the last element in the structure can be an array of unknown size, which is called a flexible array member, but the flexible array member in the structure must be at least one other member. Flexible array Members allow the structure to contain an array of variable sizes. The size of the structure returned by sizeof does not include the memory of the flexible array. The structure containing flexible array members uses the malloc () function to dynamically allocate memory, and the allocated memory should be larger than the size of the structure to adapt to the expected size of the flexible array .]
C language Daquan, "flexible array members"
Take a look at the flexible array members in the C99 standard:
An array of 0 elements -- an array of 0 Elements
Sometimes we need to generate a struct to implement a variable length structure. How to implement it?
See the definition of this struct:
Typedef struct st_type
{
Int nCnt;
Int item [0];
} Type_a;
(Some compilers may report errors and cannot compile the statements :)
Typedef struct st_type
{
Int nCnt;
Int item [];
} Type_a;
In this way, we can define a variable length structure. Only 4 is obtained using sizeof (type_a), that is, sizeof (nCnt) = sizeof (int ).
The array with 0 elements does not occupy space, and then we can perform the variable length operation.
C language:
Type_a * p = (type_a *) malloc (sizeof (type_a) + 100 * sizeof (int ));
C ++ language version:
Type_a * p = (type_a *) new char [sizeof (type_a) + 100 * sizeof (int)];
In this way, a 100-long type_a type object is generated. The variable length element can be easily accessed using p-> item [n]. The principle is very simple.
, Allocated more memory than sizeof (type_a) after int item []; has its meaning, it points to int nCnt; followed by the content, is not
Memory is needed, and the memory allocated during allocation can be controlled by it, which is a very useful technique.
Release is also simple:
C language:
Free (p );
C ++ language version:
Delete [] p;
In fact, this is called the flexible array member (fleible array member) C89 does not support this kind of thing, C99 adds it as a special case to the standard. However
Yes, C99 supports incomplete type, instead of zero array, which is equivalent to int item [0]. This form is invalid, and C99 supports
The form is the same as int item []; only some compilers support int item [0]; as non-standard extensions, and before C99 is released
After C99 is released, some compilers combine the two into one.
The following content is related to C99:
6.7.2.1 Structure and union specifiers
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. With two exceptions,
Flexible array member is ignored. First, the size of the structure shall be equal to the offset
Of the last element of an otherwise identical structure that replaces the flexible array member
With an array of unspecified length.106) Second, 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 wocould not make the structure larger than the object being accessed; the offset of
Array shall remain that of the flexible array member, even if this wowould differ from that of
Replacement array. If this array wowould have no elements, it behaves as if it had one element
The behavior is undefined if any attempt is made to access that element or to generate a pointer
One past it.
For example, if either of the two can be compiled and completed in VC ++ 6, a warning C4200: nonstandard extension is generated.
Used: zero-sized array in struct/union warning message.
In DEVCPP, the two can also be used without warning messages.