1. What is byte alignment

There are some rules for byte alignment in C structures.

Let’s start with a piece of code:

struct st1
{
	char name;
	double age;
	char sex;
};
// 32-bit sizeof(struct st1) = 16
// Sizeof (struct st1) = 24 in 64-bit
struct st2
{
	char a;
	char b;
	char c;
};
// For 32-bit and 64-bit, sizeof(struct st2) is 3 bytes
Copy the code

As can be seen from the above results, structure ST1 is aligned by 4 bytes under 32 bits, structure ST2 is aligned by 1 byte regardless of 32-bit or 64-bit.

So we can summarize the alignment rules as follows:

  • Aligns the struct with the maximum variable length of bytes in the struct, where the byte length of all struct members does not exceed the operating system’s base byte unit (4 for 32-bit and 8 for 64-bit);
  • If a variable byte in the structure exceeds the operating system base byte unit, it is aligned to the system byte unit.

Note: not all 32 bits are directly aligned to 4 bytes, while 64 bits are aligned to 8 bytes.

2. Why byte alignment

First of all, a little bit of knowledge, how much memory the CPU can read at a time depends on how many bits the data bus is. If it is 16 bits, it can only read 2 bytes at a time. If it is 32 bits, it can read 4 bytes at a time.

Suppose we have a structure that looks like this:

struct st3
{
    char a;
    int b;
};
// In 32-bit systems, it should be 8 bytes according to the rule in section 1.
Copy the code

Suppose the address space looks something like the following:

If there is no byte aligned, a takes up 0x00000001 and b takes up 0x00000002~0x000000005. If the CPU wants to read b from memory, First read the byte 0x00000005 from the starting address of variable B 0x00000002 to 0x0000004, and then read the byte 0x00000005 again. This is equivalent to reading an int. The CPU reads the byte from memory twice.

If a takes 0x00000001 and b takes 0x00000005 to 0x00000008, then the CPU reads b from 0x00000005 to 0x00000008. I just read it all at once.

So the root cause of byte alignment is that the CPU reads memory more efficiently when aligned. However, there is a problem here, that is, when the alignment of the three bytes 0x00000002~0x00000004 are wasted, so the byte alignment actually means that the point of space for time, the specific code when how to choose, in fact, depends on the individual.

3. Set alignment manually

When you need to manually set alignment:

  • For example, when two servers use the same structure for network communication, you need to manually set the alignment rules to ensure that the length of the two structures remains the same.

  • The structure of registers when writing hardware drivers;

There are two ways to manually set alignment:

  • Add precompiled flags to code:
// The usage is as follows
#pragma pack(n)// indicates that everything following it is aligned to n bytes
struct st3
{
    char a;
    int b;
};
#pragma pack()// Unalignment of n bytes is a reverse operation on #pragma pack(n)
Sizeof (st3)=5
Copy the code

The above two lines are similar to driving a car. When you get to a certain stretch of road, you find a sign that says the speed limit is 60 km. After that stretch of road, you find a sign that says the speed limit is 60 km.

  • When defining a structure:
// The usage is as follows
struct bbb
{
   char a;
   int b;
}__attribute__((packed));// Align to the actual occupied bytes, which is equivalent to 1 byte alignment
Sizeof (st3)=5
Copy the code

4. Structure comparison method

You can use the memory comparison function memcpy to compare structures, but because structure alignment may have inconsistent fill bits, you need to be aware of this:

  1. Set to 1 byte alignment so it has no space;

  2. Initialize the structure beforehand;

memcpy(char *dest, const char* src, int len); #include
      
Copy the code