The introduction
C language structure in the body of the layout is a platitude problem, the Internet also read some information, some say more vague, some are wrong. I draw lessons from the predecessors of the article, through practice, summed up some rules, if there is a mistake, hope to correct, very grateful.
The actual environment
- System environment
MacOS Sierra (10.12.4)
- IDE
Xcode (8.3)
An overview of the
Pragma pack: pragma pack: pragma pack: pragma pack: pragma pack: pragma pack: pragma pack
normal
The details of struct byte alignment depend on the specific compiler implementation, but generally follow three guidelines:
- The first address of a structure variable can be determined by the size of its widest primitive type member (
sizeof
). - The offset of each member of a structure relative to the first address of the structure
offset
Are integer multiples of the size of the member, and the compiler adds padding bytes between the members if necessary. - The total size of the structure
sizeof
Is an integer multiple of the size of the widest base member of the structure. The compiler adds padding bytes after the last member if necessary.
The following demo will explain the above rules:
code
struct student {
char name[5];
double weight;
int age;
};
Copy the code
struct school {
short age;
char name[7];
struct student lilei;
};
Copy the code
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
struct student lilei = {"lilei".112.33.20};
printf("size of struct student: %lu\n".sizeof(lilei));
printf("address of student name: %u\n",lilei.name);
printf("address of student weight: %u\n",&lilei.weight);
printf("address of student age: %u\n",&lilei.age);
struct school shengli = {70."shengli",lilei};
printf("size of struct school: %lu\n".sizeof(shengli));
printf("address of school age: %u\n",&shengli.age);
printf("address of school name: %u\n",shengli.name);
printf("address of school student: %u\n",&shengli.lilei);
}
return 0;
}
Copy the code
The output
Explain rules
- When the compiler makes space for a structure, it first finds the widest base datatype in the structure and then looks for the location of the memory address divisible by the base datatype as the first address of the structure. (In this demo
struct school
containsstruct student
, so the widest basic data type isdouble
.sizeof(double)
for8
.1606416152/8 = 200802019
.1606416112/8 = 200802014
). - Before clearing space for each member of a structure, the compiler checks whether the offset of the first address of the pre-created space relative to the first address of the structure is an integer multiple of the size of this member. If so, it places this member. If not, it fills bytes between this member and the previous member to reach the integer multiple. This is to move the first address of the pre-opened space a few bytes back (why
struct student weight
The first address of the member is1606416160
Rather than1606416157
Char arrays are 1 byte aligned, and the structure members are stored at integers multiple of their own maximum internal size, ** for examplestruct a
Are there instruct b
Members,b
Are there inChar, int, double
Wait for the members, thatb
The starting location of the storage should be an integer multiple of 8. throughstruct school
You can see the member memory distribution,school.name
The first address of the1606416114
Rather than1606416119
.school.student
The first address of the1606416128
That can be8
Divisible, cannot be divided by24
Aliquot). - The total size of the structure consists of padding bytes. The last member of the structure must satisfy the first two, but must also satisfy the third, or must fill a certain number of bytes at the end of the structure to satisfy the requirement
struct student
The number of occupied bytes is24
Rather than20
).
Distribution of memory
extension
Careful friends may find that the value of &shengli.lilei(equivalent to shengli.lilei.name) is not equal to lilei.name, In other words, the member of struct student lilei and struct student lilei in struct school shengli do not refer to the same memory space, but to a new memory space created by value copy. That is, structs are value types rather than reference type data structures. Also, the memory address shows that the memory space of the two structure variables is allocated consecutively on the memory stack.
A domain
The main purpose of structs using bit-fields is to compress storage. Bit-field members cannot be sizeof individually. C99 states that int,unsigned int, and bool can be bit-field types, but the compiler almost always extends this to allow other types to exist. Structs that contain bit-field fields must follow the following four rules in addition to the three above:
- If the word ends of adjacent bit fields have the same type and the sum of bit widths is less than the type
sizeof
Size, the latter field will be stored next to the former until it can no longer accommodate it. - If adjacent bit-field fields are of the same type, but the sum of the bit widths is greater than the type
sizeof
Size, the latter field will start from the new storage unit and its offset will be an integer multiple of its type size. - If the type of the adjacent bit-field field is different, the specific implementation varies from compiler to compiler. VC6 uses uncompressed mode, and dev-C ++ uses compressed mode.
- If bit-field fields are interspersed with non-bit-field fields, no compression is performed.
The following demo will explain the above rules:
code
typedef struct A {
char f1:3;
char f2:4;
char f3:5;
char f4:4;
}a;
Copy the code
typedef struct B {
char f1:3;
short f2:13;
}b;
Copy the code
typedef struct C {
char f1:3;
char f2;
char f3:5;
}c;
Copy the code
typedef struct D {
char f1:3;
char :0;
char :4;
char f3:5;
}d;
Copy the code
typedef struct E {
int f1:3;
}e;
Copy the code
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
printf("size of struct A: %lu\n".sizeof(a));
printf("size of struct B: %lu\n".sizeof(b));
printf("size of struct C: %lu\n".sizeof(c));
printf("size of struct D: %lu\n".sizeof(d));
printf("size of struct E: %lu\n".sizeof(e));
}
return 0;
}
Copy the code
The output
Explain rules
struct A
All bit-field member types arechar
, the first byte can only holdf1
andf2
.f3
Storage starts from the next byte, the second byte cannot accommodatef4
, sof4
It’s also stored from the next byte, sosizeof(a)
The results for3
.struct B
The median field member type is different and has been compressed, thereforesizeof(b)
The results for2
(Uncompressed mode is not validated, sorry).struct C
There are non-bit-field type members between the median field members, which are not compressed, sosizeof(c)
So that’s 3.struct D
Is there a named domain member in,char f1:3
Account for3
abit
.char :0
Move to the next1
The unit of movement depends on the bit-field type,short
Move to the next2
Bytes,int
Move to the next4
Bytes),char :4
Account for4
abit
And then can’t accommodatechar f3:5
So save it1
Bytes, sosizeof(d)
The results for3
.- Some of you might wonder, why
sizeof(e)
The results for4
It should not just occupy1
A byte? Don’t forget the aboveRule 3.
Matters needing attention
- The address of the bit-field is not accessible, so the & operator is not allowed for the bit-field. You cannot use Pointers to bitfields or arrays of bitfields (arrays are special Pointers).
- Bitfields cannot be returned as a result of a function.
- The bitfield is in units of the defined type, and the length of the bitfield cannot exceed the length of the defined type. Such as the definition
int a:33
It’s not allowed. - A bitdomain may not specify a bitdomain name, but nameless bitdomains cannot be accessed. Nameless bit fields can only be filled or repositioned, depending on the type. For example,
char:0
Indicates that the entire bit field is pushed back by one byte, that is, the next bit field after the nameless bit field is stored from the next byte, and so onshort:0
andint:0
Represents the entire bitfield pushed back by two and four bytes, respectively. When the length of the vacancy field is a specific value N (e.gint:2
), this variable is used for N bits only.
Pragma Pack preprocessor macros
The compiler’s #pragma pack directive is also used to adjust the alignment of structures, with slightly different compiler names and usages. Using the #pragma pack(n) directive, the compiler will align n bytes with values 1, 2, 4, 8, 16, default 8, and uncustomize byte alignment using the #pragma pack() directive. If set to #pragma Pack (1), the structure has no padding bytes, enabling “seamless storage” of space, which is friendly and compatible for transferring data across platforms. The structure contains the #pragma Pack preprocessor macro, which follows the following two rules in addition to the three above:
- If n is greater than or equal to the number of bytes used by the member type, the offset must meet the default alignment. If n is less than the number of bytes used by the member type, the offset must be a multiple of n and does not meet the default alignment. The offset of a structure member should be the smallest of the two, as follows:
offsetof(item) = min(n, sizeof(item))
- For the total size of the structure, if n is greater than the number of bytes taken up by all member types, then the total size of the structure must be a multiple of the number of bytes taken up by the largest member, otherwise it must be a multiple of N.
usage
#pragma pack(push) // Set the current alignment
#pragma pack(pop) // Remove the current alignment when packing stack is removed
#pragma pack(n) //n=1,2,4,8,16 saves the current alignment and sets the alignment to n bytes
#pragma pack() // Pack (pop)
#pragma pack(push,n)Pack (push) + pack(n)
Copy the code
code
#pragma pack(4)
typedef struct F {
int f1;
double f2;
char f3;
}f;
#pragma pack()
Copy the code
#pragma pack(16)
typedef struct G {
int f1;
double f2;
char f3;
}g;
Copy the code
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
printf("size of struct D: %lu\n".sizeof(f));
printf("size of struct E: %lu\n".sizeof(g));
}
return 0;
}
Copy the code
The output
Explain rules
struct F
The alignment is set to4
.min(4, sizeof(int)) = 4
.f1
Account for4
The offset is0
.min(4, sizeof(double)) = 4
.f2
Account for4
The offset is4
.min(4, sizeof(char)) = 1
.f3
Account for1
The offset is12
And finally the whole structure satisfiesRule 3.sizeof(f) = 16
.struct G
The alignment is set to16
Is larger than any member type in the structuresizeof(f) = 24
.
conclusion
Bitfields and **#pragma pack preprocessor macros have their own rules to follow as long as they follow the three guidelines **. Structure members are arranged in order to save as much space as possible.
Refer to the link
Blog. Sina. Cn/dpool/blog /… C.biancheng.net/cpp/html/46… Hubingforever.blog.163.com/blog/static…