Variable-length structural body

Source: Internet
Author: User


In a Linux system,/usr/include/linux/if_pppox.h has such a structure:

struct Pppoe_tag {

__u16 Tag_type;

__u16 Tag_len;

Char tag_data[0];

} __attribute ((packed));

The last member is a variable-length array, which is best defined in this way for the structure of the TLV (type-length-value) Form or for other structures that require variable lengths. Very convenient to use, when created, malloc a structure size plus variable length of data length of the space to it, variable-length parts can be accessed as an array, release, the entire structure can be free. Examples are as follows:

struct Pppoe_tag *sample_tag;

__u16 Sample_tag_len = 10;

Sample_tag = (struct Pppoe_tag *) malloc (sizeof (struct Pppoe_tag) +sizeof (char) *sample_tag_len);

Sample_tag->tag_type = 0xFFFF;

Sample_tag->tag_len = Sample_tag_len;

Sample_tag->tag_data[0]= ....

...

When released,

Free (Sample_tag)


Can I replace it with Char *tag_data. In fact it and Char *tag_data is a big difference, in order to illustrate this problem, I wrote the following program:

Example 1:test_size.c

Ten struct TAG1

20 {

int A;

+ int B;

}__attribute ((packed));

60

Tag2 struct

80 {

int A;

+ int B;

*c Char;

}__attribute ((packed));

130

TAG3 struct

150 {

int A;

int b;

C[0 Char];

}__attribute ((packed));

200

TAG4 struct

220 {

int A;

int b;

(+ char c[1];

260}__attribute ((packed));

270

280 int Main ()

290 {

Tag2 L_tag2 of a struct;

310 struct TAG3 l_tag3;

The l_tag4 of the tag4 struct;

330

340 memset (&l_tag2,0,sizeof (struct tag2));

memset (&l_tag3,0,sizeof (struct tag3));

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

+ 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);

("L_tag4 =%p,l_tag4.c =%p\n", &l_tag4,l_tag4.c);

Exit (0);

460}


__attribute ((packed)) is intended to force No 4-byte alignment, which makes it easier to explain the problem.

The running results of the program are as follows:

Size of Tag1 = 8

Size of Tag2 = 12

Size of Tag3 = 8

Size of Tag4 = 9

L_tag2 = 0xbffffad0,&l_tag2.c = 0xbffffad8,l_tag2.c = (nil)

L_tag3 = 0XBFFFFAC8,L_TAG3.C = 0xbffffad0

L_tag4 = 0xbffffabc,l_tag4.c = 0xbffffac4


From the above program and running results can be seen: Tag1 itself consists of two 32-bit integers, so accounted for 8 bytes of space. The TAG2 consists of two 32-bit integers, plus a char * pointer, so it takes 12 bytes. Tag3 is really see the difference between Char C[0] and Char *c, Char c[0] in C is not a pointer, is an offset, this offset points to a, B immediately after the space, so it actually does not occupy any space. Tag4 adds to this point in more details. Therefore, if the last member of the above struct Pppoe_tag is defined with Char *tag_data, it will be inconvenient to use in addition to a pointer variable that takes up 4 bytes:


Method One, when created, you can first allocate a piece of memory for the struct Pppoe_tag, and then allocate the memory for Tag_data, so that in the release, the Tag_data occupied memory is released first, and then the memory occupied by the Pppoe_tag is released;


Method Two, when created, directly for the struct pppoe_tag allocation of a struct Pppoe_tag size plus tag_data memory, from the example of 420 lines can be seen, tag_data content to be initialized, to let Tag_data point to STRCT The memory behind the Pppoe_tag.

struct Pppoe_tag {

__u16 Tag_type;

__u16 Tag_len;

Char *tag_data;

} __attribute ((packed));


struct Pppoe_tag *sample_tag;

__u16 Sample_tag_len = 10;

Method One:

Sample_tag = (struct Pppoe_tag *) malloc (sizeof (struct pppoe_tag));

Sample_tag->tag_len = Sample_tag_len;

Sample_tag->tag_data = malloc (sizeof (char) *sample_tag_len);

Sample_tag->tag_data[0]= ...

When released:

Free (sample_tag->tag_data);

Free (Sample_tag);


Method Two:

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 = ((char *) sample_tag) +sizeof (struct pppoe_tag);

Sample_tag->tag_data[0]= ...

When released:

Free (Sample_tag);

So no matter how that method is used, there is no such definition as char tag_data[0].


Speaking so much, in essence involves a C language inside the array and pointer to the difference between the problem (that is, we mentioned the memory management problem, the array is allocated in the structure of the space after the spatial address of a continuous space, and the pointer is in a random space allocation of a continuous space). Char A[1] A and char *b B are the same. "Programming abstractions in C" (Roberts, E. S., Mechanical industry Press, 2004.6) 82 pages, "ARR is defined to being identical to &arr[0]". In other words, Char a[1] A is actually a constant, equal to &a[0]. While Char *b is a real pointer to variable B exists. So, a=b is not allowed, and b=a is allowed. Both variables support subscript access, so the a[0] and b[0] are inherently different. We can use an example to illustrate this.


Example two:

Ten #include <stdio.h>

#include <stdlib.h>

30

+ int Main ()

50 {

-Char a[10];

*b Char;

80

A[2]=0xfe;

B[2]=0xfe;

Exit (0);

120}



But when an array is a parameter, there is no difference between the pointer.

int Do1 (char a[],int len);

int Do2 (char *a,int len);

There is no difference between a in these two functions. is a pointer variable that is actually present.


By the way, the definition of the last member of the struct Pppoe_tag is char tag_data[0], and some compilers do not support the definition of an array of length 0, in which case it can only be defined as Char tag_data[1], using the same method.


In the source code of OpenOffice See the following data structure, is a Unicode string structure, his last use of the length of 1 arrays, may be for compatibility or cross-compiler.


typedef struct _RTL_USTRING

{

Sal_int32 RefCount;

Sal_int32 length;

Sal_unicode Buffer[1];

} rtl_ustring;

This is a variable length string. This is probably what it means:


rtl_ustring * str = malloc (256);

Str->length = 256;

Str->buffer now points to a buffer of length 256-8



Summary: Through the above reprinted article, can be clearly found that the advantages of this method is actually to simplify the memory management, we assume that in the ideal memory state, then the allocation of memory space, can be ordered down (of course, Actually because of memory fragmentation and other reasons will be different) we can use the last array of pointers directly without interval to jump to the allocated array buffer, which is very common under Linux, under the Windows I just saw in MFC similar, other cases do not remember clearly, only remember that the MFC is said , can be used to assign the structure of the pointer (this) directly +1 (The detailed method please see my blog: The CE classification: Memory Pool technology Application and detailed description), jumped to the actual memory space, originally also thought for a long day, so said, a lot of things seem very complex, in fact, is the basis of things, to play a solid foundation, This is the lofty high-rise valerian lofty premise and protection, learning is also, should not be ambitious, should be down-to-earth, step-by-step forward, but also to summarize their own experience and experience, theory and practice of mutual proof, can go farther, see more beautiful scenery.


Finally, thanks again for the selfless sharing of children's shoes online ...



Flexible array Structure Member collection

"Flexible Array structure members

In C99, the last element in the struct allows an array of unknown size, which is called a flexible array member, but a flexible array member in the structure must precede at least one other member. Flexible array members allow a variable-sized array to be included in the structure. The size of this structure returned by sizeof does not include the memory of a flexible array. Structures that contain flexible array members are dynamically allocated with the malloc () function, and the allocated memory should be larger than the size of the structure to accommodate the expected size of the flexible array. 】

C Language Encyclopedia, "flexible Array members"


"Flexible Array structure members

In C99, the last element in the struct allows an array of unknown size, which is called a flexible array member, but a flexible array member in the structure must precede at least one other member. Flexible array members allow a variable-sized array to be included in the structure. The size of this structure returned by sizeof does not include the memory of a flexible array. Structures that contain flexible array members are dynamically allocated with the malloc () function, and the allocated memory should be larger than the size of the structure to accommodate the expected size of the flexible array. 】

C Language Encyclopedia, "flexible Array members"


Look at the flexible array members in the C99 standard:


The magic of the structural body's length--an array of 0 elements

Sometimes we need to produce a structure that implements a variable-length structure. How to achieve it.

Look at the definition of this structure:

typedef struct ST_TYPE

{

int ncnt;

int item[0];

}type_a;

(some compilers will fail to compile the error can be changed to:)

typedef struct ST_TYPE

{

int ncnt;

int item[];

}type_a;

So we can define a variable-length structure, with sizeof (TYPE_A) to get only 4, that is sizeof (NCNT) =sizeof (int) that


An array of 0 elements does not occupy space, and then we can do a variable length operation.

C language version:

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)];

So we have a 100-type_a type of thing with P->item[n] to simply access variable-length elements, the principle is very simple


, allocated more than sizeof (TYPE_A) after the memory int item[]; it has meaning, it points to the int ncnt; The following is not


There is memory required, and in the allocation of more allocated memory can be manipulated by it, is a very useful technique.

And the release is equally simple:

C language version:

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 it as a special case to join the standard. But


Yes, C99 supports the incomplete type, not the zero array, which is the same as int item[0]; This form is illegal, C99 supports


The form is the same as int item[]; only some compilers put int item[0], supported as a non-standard extension, and before C99 was released.


This non-standard extension, after C99 release, some compilers merge the two.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.