Bit segment and size end

Posted by Lucidnight on Sat, 30 Oct 2021 16:07:51 +0200

1. Bit segment

During the interview with ZTE, I was asked about the content of the paragraph. I didn't know anything about the paragraph at that time. Let's make a summary today.

Firstly, bit segment is a definition method of structure to save memory. It is widely used in computer networks. The following examples are given.

For example, we now have three shaping variables, whose ranges are 0 ~ 15, 0 ~ 10 and 0 ~ 254 respectively. We know that the number range represented by unsigned char is 0 ~ 254. Therefore, we can save these three variables with three members of unsigned char type. The definitions are as follows:

struct S {     unsigned char val1;     unsigned char val2;     unsigned char val3 ; };

We can calculate that the memory occupation size of the above structure is 3 bytes, a total of 24 bits. We know that 15 only needs 4 bits and 10 only needs 4 bits. Therefore, the bit segment is born. We can define the code of the above structure as follows and output its memory size:

#include <stdio.h>

struct S {
    unsigned char val1 : 4;
    unsigned char val2 : 4;
    unsigned char val3 ;
};

int main()
{
    struct S s;
    s.val1 = 15;
    s.val2 = 10;
    s.val3 = 127;
    printf("sizeof(struct S) = %d \n", sizeof(struct S));
    printf("s.val1 = %d \n", s.val1);
    printf("s.val2 = %d \n", s.val2);
    printf("s.val3 = %d \n", s.val3);
    return 0;
}

The running result of the above code is:

Through the definition of bit segment, the size of structure is saved from 3 bytes to 2 bytes. Through the verification of assignment, the above definition can fully meet the requirements of variables. In computer network, TCP packet encapsulation is applied to bit segment.

A bit segment is a variable type, usually char, int,   Unsigned int and assigned char types are divided into multiple bits to operate. For example, unsigned int types can be divided into 32 bits. However, C language does not specify whether 32 bits are taken from left to right or from right to left. Therefore, attention should be paid to the problem of transplantation when using bit segments. Try not to cross platform when using bit segments.

2. Large and small end problems

When it comes to bits, another important knowledge point is the problem of large and small ends. Large end storage: low byte content is stored at the high address, and high byte content is stored at the low address. That is, low to high, high to low. The small end mode is just the opposite.

For example: int val = 0x11223344;

If it is the small end storage mode, the byte storage mode in the memory is 44 33 22 11 (from left to right address from low to high). If it is the large end storage mode, the storage mode in the memory is 11 22 33 44. Generally, the X86 architecture adopts the small end storage mode, and the large end mode is usually used in the network. Therefore, in the Linux system, the data processing of network programming requires large and small end conversion, and the Linux kernel also integrates the large and small end conversion functions ntohl() and htonl(). The following is an example to illustrate the large and small end storage mode:

#include <stdio.h>

int main()
{
    int val1 = 0x11223344;
    char val2 = (char)val1;
    printf("%x\n", val2);
    
    return 0;
}

The running result of the code is:

The above code shows that my compiler uses small end storage. The 4-byte storage method for integer numbers is 44 33 22 11, and the low address storage is 0x44. Therefore, the char type assigned from valu1 to val2 takes only the low byte, and the answer is 0x44. This method can also be used to judge whether the current machine is large end storage or small end storage. The following is a complete verification code:

#include <stdio.h>

int main()
{
    int val1 = 1;
    if (1 == *(char*)(&val1)) {
        printf("Small end mode\n");
    } 
    if (0 == *(char*)(&val1)) {
        printf("Big end mode\n");
    }
    
    return 0;
}

Of course, it can also be verified through the public body. The following code Description:

#include <stdio.h>

union UN{
    int val1;
    char ch;
};
int main()
{
    union UN un;
    un.val1 = 1;
    if (1 == un.ch) {
        printf("Small end mode\n");
    } else if (0 == un.ch) {
        printf("Big end mode\n");
    }
    return 0;
}

Code run result:

  3. Bit operation priority

When writing code, you can usually solve the priority problem with parentheses. At that time, you were suddenly asked during the interview and were confused. Therefore, the following priority of bit operation is emphasized:~   > & > ^ > | , That is, the operation level of non is greater than and greater than XOR and greater than or. The priority order of logical operators is the same, that is:! > & & >||

  We realize the conversion of the size end through bit operation:

#include <stdio.h>

int main() {
    int val = 0x11223344;//Small end storage mode, from low to high address, the contents stored in single byte memory are 44 33 22 11 
    int convertVal = 0;   
    convertVal = ((val & 0xff) << 24)  //Take 8 lower bits, move 16 left bits, press bit&The priority of is lower than that of the shift left operator, so be sure to add parentheses
                   | ((val & 0xff00) << 8) //Take the lower 8 bits and move left 8 bits
                   | ((val & 0xff0000) >> 8) //Take the next highest 8 bits and shift it to the right 8 bits
                   | ((val & 0xff000000) >> 24);//8 bits higher and 16 bits right
    
    printf("convertVal = 0x%x",convertVal);
    return 0;
        
}

The running result of the code is:

 

 

 

Topics: C++