[C Language] Memory issues related to structures (2/2)

This learning goal

1.Structure memory alignment (hot interview questions)
2.Structure implementation bit segment

Please add image description

Article directory

      • This learning goal
        • 1.Structure memory alignment (hot interview questions)
        • 2.Structure implementation bit segment
    • 1. Structure memory alignment
        • 1.What rules exist for memory alignment?
        • 2.Why does memory alignment exist?
      • 1.1 Memory alignment rules
      • 1.2 What is the significance of memory alignment
    • 2. Structure implementation segments
      • 2.1 What is a bit segment?
      • 2.2 Memory allocation of bit segments
      • 2.3 Cross-platform issues in bit segments
      • 2.4 Application of bit segments
      • 2.5 Precautions for using bit segments
      • That’s it for this article, thank you for watching! If you are interested, please stay tuned for sharing about the remaining custom types!

1. Structure memory alignment

This requires us to master two knowledge points!

1.What are the rules for memory alignment?
2.Why does memory alignment exist?

1.1 Memory alignment rules

Dry information:

1.The first member of the structure is aligned at an offset of 0 relative to the address of the structure member

2.Structure members need to be aligned to an integer multiple of the alignment number

3.The total size of the structure is a positive multiple of the maximum alignment number

4.If there is a nested structure, the space occupied by the nested structure needs to be aligned to an integer multiple of its own maximum alignment number. At the same time, when calculating the total size of the structure, the nested structure’s The maximum number of alignments is also included in the comparison

Note: Alignment number = the smaller of the compiler’s default alignment number and the size of the member variable

In the vs environment, the system default alignment is 8

There is no default alignment number in Linux, the alignment number is the size of the member itself

The dense text really discouraged me! It doesn’t matter, let’s draw pictures and code to help us understand better

Everyone think about it first, what is the answer below?
struct S1
{<!-- -->
 char c1;
 int i;
 char c2;
};
printf("%d\
", sizeof(struct S1));

struct S2
{<!-- -->
 char c1;
 char c2;
 int i;
};
printf("%d\
", sizeof(struct S2));

struct S4
{<!-- -->
 char c1;
 struct S2 s2;
 double d;
};
printf("%d\
", sizeof(struct S2));
Only thinking more is the greatest help to yourself

Answer: 12, 8, 24

Drawing understanding (note that the numbers in the picture only represent the offset at the address of the structure variable):

Please add image description

Please cooperate with the above text to explain and understand! How is the total size of the structure calculated?

Let’s take another look at how the size of a structure nested structure is calculated!

Please add image description

The above content needs to be studied more!

1.2 What is the significance of memory alignment

Most of the references say this:

1.Platform reasons (transplantation reasons): Not all hardware platforms can access any data at any address; some hardware platforms only Can fetch certain types of data at certain addresses, otherwise a hardware exception will be thrown
2.Performance reasons: Data structures (especially stacks) should be aligned on natural boundaries as much as possible. The reason is that to access unaligned memory, the processor requires two memory accesses; aligned memory accesses require only one access. Assuming that a processor always takes 8 bytes from memory, the address must be a multiple of 8. If we can ensure that the addresses of all double type data are aligned to multiples of 8, then a memory operation can be performed to read or write the value. Otherwise, we may need to perform two memory accesses because the object may be divided into two 8-byte memory blocks. Generally speaking: the memory structure of the structure is to trade space for time.

It’s enough to have a general understanding here. Draw a picture below for a better understanding

Another day of being persuaded to quit by dense texts! It’s okay, let’s use animations to understand! ! ! (Blue is the space occupied by i)Please add a picture description

Look at the above situation of accessing the data in memory. The above is accessed in four bytes. If there is no memory alignment, then it takes two times to get the data in i. If If memory alignment exists, it is required once.

The default alignment number of the system. Can the default alignment number be modified manually?

Answer:Of course it is possible, we just need to apply it to our preprocessing instructions #pragma

1.First of all, the function of the #pragma directive is: is used to specify computer or operating system-specific compiler functions

2.By definition, #pragma directives are computer or operating system specific and are usually different for each compiler

3.The #pragma directive can be used in conditional statements to provide new preprocessor functionality, or to provide implementation-defined information to the compiler,

Next, let’s implement it with code!

#include <stdio.h>
#pragma pack(1)//Set the default alignment number to 1
struct S
{<!-- -->
    char c1;
    int i;
    char c2;
};
#pragma pacK()//Cancel the default alignment number and restore it to the default alignment number
int main()
{<!-- -->
    printf("%d\
",sizeof(struct S));
    return 0;
}
So what is the answer? After reading it, you can go down and try it yourself!

Note: When the alignment of the structure is inappropriate, we can change the default alignment

In the process of learning C language, we learned that we can use the method of pointer 1-pointer 2 (pointer 2 points to the first position) to get how much pointer 1 has moved from the starting position!

So is there a way to know the offset of the structure combined with the above?

I have to mention the function offsetof() macro. What does it mean here?

Solution: Function declaration–>need to use header file

size_t offsetof(type,member);

Macro definition

#define offsetof(TYPE,MEMBER) ((size_t) & amp;((TYPE*)0)->MEMBER)

If you want to know more, you can refer to this blog Offsetof macro detailed explanation – CSDN blog. This article is only responsible for how to use the Offsetof() macro to calculate the offset of a member address of the structure.

Code implementation:

#include <stdio.h>
#include <stddef.h>
struct S
{<!-- -->
    char a;
    int i;
};
int main()
{<!-- -->
    printf("%d\
",offsetof(struct S,i));
    //Then the result here is 4
    return 0;
}

Looking back, it turns out that memory alignment is really killing the enemy by a thousand, but doing a loss of eight hundred! So is there any way to avoid or reduce space waste? This has something to do with the position we are going to talk about next.

2. Structure implementation segments

2.1 What is the bit segment

The function of the bit segment is similar to that of the structure, and it can save space very well, but there is the problem of cross-platform of the bit segment

The bit segment can be said to be a deformation of the structure, and its usage is basically the same as the structure. It is just different from the structure in memory allocation. The declaration of the bit segment and the structure are similar, but there are two differences.

1. On members: int, unsigned int or signed int, but in C99 you can choose other types

2. Format: There is a colon and a number after the segment member name

Code:

struct A
{<!-- -->
    char_a:2;
    char_b:5;
};

The variable name here can also be removed directly. It is for the readability of the code and allows users to better understand the structure type
The numbers here do not represent bytes, but bits

Then A here is considered a bit segment type

Question: How much memory does segment A occupy? printf("%d\
", sizeof(struct A));

Don’t rush to answer here, let’s learn further! Come to the answer together!

Please add image description

Memory allocation for 2.2-bit segments

1.Bit segment members: int, unsigned int, signed int or char and other types (need to be an integer and converted to binary)

2.The size of the bit segment space is usually allocated in four bytes or one byte

3.Bit segments involve many uncertain factors. Bit segments are not cross-platform. Pay attention to portable programs and avoid using bit segments

Cross-platform issues in 2.3 bit range

Uncertain factors generally include:

1.Is the direction of memory storage from left to right or right to left

2.Is it from a low address to a high address, or from a high address to a low address

3.The int type is not sure whether it is treated as a signed number or an unsigned number

4.When a structure includes two bit fields, and the second bit field is larger and cannot accommodate the remaining space of the first bit field, should we discard or use the remaining space? This is uncertain

5. The maximum number of bits in the bit field cannot be determined (the maximum number of bits in a 16-bit machine is 16, and the maximum number in a 32-bit machine is 32. If it is written as 27, there will be a problem on a 16-bit machine), and it may rush out. Maximum scope, problems occur

We might as well measure the data in the vs2013 environment

Under vs2013, the bit segment is from left to right, from low address to high address. The space required by the bit segment is insufficient, so directly open up a new space. Let’s understand it based on the picture.

Please add image description

Steps:

1.First, open eight bits in the bit field (this is the case of char type)

2.How many bits does the number after the bit segment member occupy?

3.Assign a value to the structure members, convert the value into binary form, and store it according to (2) The middle segment members occupy multiple bits

4.About (4) of the above uncertain factors, vs2013 chooses to discard it, then open up a new space and repeat steps (1, 2, 3)

Application of 2.4 bit segment

For example, in the network protocol in the figure below, there are many effects that can be achieved with only a few bits in a structure. Here, the desired effect can be achieved by using bit segments, and Can save space waste. At the same time, the data size transmitted over the network will be smaller, improving the smoothness and efficiency of the network!

Please add image description

Notes on the use of 2.5 bit segments

struct A
{<!-- -->
    int _a:2;
    int _b:5;
};
int main()
{<!-- -->
    //wrong approach
   struct A s={<!-- -->0};
    scanf("%d", & amp;s._a);
    
    //Correct demonstration
    int b=0;
    scanf("%d", & amp;b);
    s._b=b;
return 0;
}

The reasons are as follows:

1.Multiple bit segment members occupy one byte. Not every bit segment position is the starting position of a certain byte or has an address

2.The memory assigns an address to each character, and there is no address for the bits inside a byte

3.For bit segment members that do not have addresses, the address cannot be obtained directly & amp;

Solution:

Answer: You can put the value into a variable and then assign it to the bit segment member. This assignment is very clever in future operations.

That’s it for this article, thank you for watching! If you are interested, please stay tuned for sharing about the remaining custom types!