Research on a method of assigning memory to structures based on C++

This article discusses a method of assigning memory to structures based on C++. Through this method, while assigning memory, it is more friendly to code reading, can be applied to some actual working environments, and can improve development efficiency and reduce maintenance costs. .

Ask a question

In a certain iteration of a certain project, a function needs to be added. This function cannot be made into a separate module and must be judged and processed in different module functions. In the initial implementation version, a parameter is added at the end of the corresponding function and a default value is set, so that the purpose can be achieved without affecting the original logic. However, there were many modules involved, and during the code review, it was rejected by the supervisor. When it was implemented this way, first, it was the first time to come into contact with engineering code. There was a lot of engineering code, and it needed to be familiar with it and master how to change it in a short period of time. Starting with the function parameters was the fastest and easiest way.

After thinking about it, I found that the original function has a large structure parameter with reserved fields, and the buffer is large enough. However, some addresses have been assigned and obtained, and the address offset is already fixed, such as Chapter 68 4 bytes from the beginning of the byte, etc.

Program description

You can assign and read the specified offset in the buffer. For example, fix the 0th field as a flag field to indicate whether to sort. But this is unsafe. If there is no assignment, but it is contaminated by other data and it is exactly 1, it will affect the code logic.

Therefore, consider using the form sort=1;foo=xxx;bar=yyy;. When sort= appears, the following 1 byte is required. . This enhances the judgment of data accuracy through multiple bytes. The advantage is that there is no length limit and it is intuitive and convenient, but it requires parsing and comparing strings to get the required content.

However, the above form applies to strings. If you want to pass an address pointer (in C++, it is common to pass pointers), you need to convert the address value into a string, and then convert the string into a numerical form when reading. , more troublesome.

Finally, a custom structure method is used, and fields corresponding to offsets are used. For unused offset addresses, reserved fields are used. However, there are also disadvantages, that is, the structure needs to be designed manually, and once it is determined, it cannot be easily changed, and the content is of a fixed length (you can reserve some space as appropriate). See details below.

Project code

Design ideas

Here, combined with the code description idea, the custom structure StructInfo_tt lists the fields and corresponding values as required, and sets tagXXX and valXXX. The former is in the form of foo=, and its length is 4; the latter is assumed to be a pointer, considering 32-bit and 64-bit compatibility, and the length is set to 8.

Map memory directly to the structure through StructInfo_t *myptr = (StructInfo_t *)buffer; (C++ is so convenient), through memcpy(myptr->tagFoo, "foo=\ ", sizeof(myptr->tagFoo)); memcpy(myptr->valFoo, & amp;mybuf, sizeof(myptr->valFoo));Copy the corresponding field.

Reading is similar.

Implementation code

Complete code:

#include <stdio.h>
#include <stdlib.h>

#include <string.h>

#define DEFWIDTH 16 /* Default # chars to show per line */
#define MAXWIDTH 32 /* Maximum # of bytes per line */
/**
Output example:
Address: character hexadecimal printable characters
new buffer print: 70
0x0012FAE4: 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 .PNG.....IHDR
0x0012FAF4: 00 00 00 f0 00 00 01 40 08 02 00 00 00 0d 8a 66 [email protected]
0x0012FB04: 04 00 00 20 00 49 44 41 54 78 da ed 7d 3d 68 24 ... .IDATx..}=h$
0x0012FB14: 01 02 03 04 05 06 07 08 09 0a 0b ...........
*/
void dump(const char *buffer, int len)
{
    int i, j, n;
    int line = DEFWIDTH;
    char c;
    unsigned char* buf = (unsigned char *)buffer; // Must be unsigned char type

    n = len / line;
    if (len % line)
        n + + ;

    for (i=0; i<n; i + + )
    {
        //printf("0x x: ", (unsigned int)(buf + i*line)); // linux ok
        printf("0x%8p: ", buf + i*line); // windows ok
        
        for (j=0; j<line; j + + )
        {
            if ((i*line + j) < len)
                printf(" x ", buf[i*line + j]);
            else
                printf(" ");
        }

        printf(" ");
        for (j=0; j<line & amp; & amp; (i*line + j)<len; j + + )
        {
            if ((i*line + j) < len)
            {
                c = buf[i*line + j];
                printf("%c", c >= ' ' & amp; & amp; c < '~' ? c : '.');
            }
            else
                printf(" ");
        }

        printf("\\
");
    }
}

// Custom structure
typedef struct StructInfo_tt
{
char tagFoo[4]; // foo=
char valFoo[8]; // ptr
char tagBar[4]; // bar=
char valBar[4]; // size ptr
char tagName[8]; // LaTeLee=
char valName[6]; // 250
\t
char reserve[216]; // left
} StructInfo_t;

char buffer[250] = {0};

void set_struct(char* mybuf, int bufsize)
{
    // char* bufptr = mybuf;
    // int bufsize = 250;
    StructInfo_t *myptr = (StructInfo_t *)buffer;
memcpy(myptr->tagFoo, "foo=", sizeof(myptr->tagFoo));
memcpy(myptr->valFoo, & amp;mybuf, sizeof(myptr->valFoo));

    memcpy(myptr->tagBar, "bar=", sizeof(myptr->tagBar));
memcpy(myptr->valBar, & amp;bufsize, sizeof(myptr->valBar));
    
    char tmpName[8] = "520250";
memcpy(myptr->tagName, "LaTeLee=", sizeof(myptr->tagName));
memcpy(myptr->valName, tmpName, sizeof(myptr->valName));
    
    printf("mybuf ptr: %p\\
", mybuf);
    dump((const char *)myptr, 64);
}

void get_struct()
{
char *bufptr = NULL;
int bufsize = 0;
    
    StructInfo_t *myptr = (StructInfo_t*)buffer;
if(strncmp(myptr->tagFoo, "foo=", sizeof(myptr->tagFoo)) == 0)
{
// memcpy( & amp;bufptr, myptr->valFoo, sizeof(myptr->valFoo));
memcpy( & amp;bufptr, myptr->valFoo, sizeof(char*));
}
if(strncmp(myptr->tagBar, "bar=", sizeof(myptr->tagBar)) == 0)
{
memcpy( & amp;bufsize, myptr->valBar, sizeof(myptr->valBar));
}
    
    memcpy(bufptr, "this is hello from hell", bufsize);
    printf("got ptr: %p size: %d\\
", bufptr, bufsize);
    dump((const char *)myptr, 64);
}

Test environment

32-bit:

# uname -a
Linux debian 3.2.0-4-686-pae #1 SMP Debian 3.2.65-1 + deb7u1 i686 GNU/Linux
# g++ --version
g++ (Debian 4.7.2-5) 4.7.2

64-bit:

$ uname -a
Linux master 3.10.0-957.27.2.el7.x86_64 #1 SMP Mon Jul 29 17:46:05 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
$ g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)

Test code

The buffer is large enough:

int main(void)
{
    printf("struct value test, sizeof(char*): %d sizeof(int): %d\\
", sizeof(char*), sizeof(int));
    char mybuf[64] = {0};
    int bufsize = 64;
    set_struct(mybuf, bufsize);
    get_struct();
    
    printf("out mybuf [%s]\\
", mybuf);
    dump((const char *)mybuf, 64);
    
    return 0;
}

Test Results:

struct value test, sizeof(char*): 8 sizeof(int): 4
mybuf ptr: 0x7fffd9638240
0x0x601080: 66 6f 6f 3d 40 82 63 d9 ff 7f 00 00 62 61 72 3d [email protected]=
0x0x601090: 40 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 @...LaTeLee=5202
0x0x6010a0: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x6010b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
got ptr: 0x7fffd9638240 size: 64
0x0x601080: 66 6f 6f 3d 40 82 63 d9 ff 7f 00 00 62 61 72 3d [email protected]=
0x0x601090: 40 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 @...LaTeLee=5202
0x0x6010a0: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x6010b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
out mybuf [this is hello from hell]
0x0x7fffd9638240: 74 68 69 73 20 69 73 20 68 65 6c 6c 6f 20 66 72 this is hello fr
0x0x7fffd9638250: 6f 6d 20 68 65 6c 6c 00 67 6f 74 20 70 74 72 3a om hell.got ptr:
0x0x7fffd9638260: 20 25 70 20 73 69 7a 65 3a 20 25 64 0a 00 6f 75 %p size: %d..ou
0x0x7fffd9638270: 74 20 6d 79 62 75 66 20 5b 25 73 5d 0a 00 00 00 t mybuf [%s]....

Observation: The pointer length of the running system is 8 bytes, and the int type is 4 bytes. Pointers and sizes are passed correctly.

Buffer is smaller:

int main(void)
{
    printf("struct value test, sizeof(char*): %d sizeof(int): %d\\
", sizeof(char*), sizeof(int));
    char mybuf[16] = {0};
    int bufsize = 16;
    set_struct(mybuf, bufsize);
    get_struct();
    
    printf("out mybuf [%s]\\
", mybuf);
    dump((const char *)mybuf, 64);
    
    return 0;
}

Test Results:

struct value test, sizeof(char*): 8 sizeof(int): 4
mybuf ptr: 0x7ffd3992b880
0x0x601080: 66 6f 6f 3d 80 b8 92 39 fd 7f 00 00 62 61 72 3d foo=...9....bar=
0x0x601090: 10 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 ....LaTeLee=5202
0x0x6010a0: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x6010b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
got ptr: 0x7ffd3992b880 size: 16
0x0x601080: 66 6f 6f 3d 80 b8 92 39 fd 7f 00 00 62 61 72 3d foo=...9....bar=
0x0x601090: 10 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 ....LaTeLee=5202
0x0x6010a0: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x6010b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
out mybuf [this is hello fr
0x0x7ffd3992b880: 74 68 69 73 20 69 73 20 68 65 6c 6c 6f 20 66 72 this is hello fr
0x0x7ffd3992b890: 80 b9 92 39 fd 7f 00 00 00 00 00 00 10 00 00 00 ...9............
0x0x7ffd3992b8a0: 00 00 00 00 00 00 00 00 55 15 39 d7 40 7f 00 00.....U.9.@...
0x0x7ffd3992b8b0: 00 00 00 00 00 00 00 00 88 b9 92 39 fd 7f 00 00 .........9....

illustrate:

Because mybuf is less, the bottom layer is copied according to the actual size. The string this is hello fr is 16 bytes, but there is no \0 at the end, so the line cannot be wrapped correctly ( Also visible from binary printing).

32-bit test

The buffer area is sufficient:

struct value test, sizeof(char*): 4 sizeof(int): 4
mybufptr: 0xbfcac45c
0x0x8049e20: 66 6f 6f 3d 5c c4 ca bf 40 00 00 00 62 61 72 3d foo=\[email protected]=
0x0x8049e30: 40 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 @...LaTeLee=5202
0x0x8049e40: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x8049e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
got ptr: 0xbfcac45c size: 64
0x0x8049e20: 66 6f 6f 3d 5c c4 ca bf 40 00 00 00 62 61 72 3d foo=\[email protected]=
0x0x8049e30: 40 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 @...LaTeLee=5202
0x0x8049e40: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x8049e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
out mybuf [this is hello from hell]
0x0xbfcac45c: 74 68 69 73 20 69 73 20 68 65 6c 6c 6f 20 66 72 this is hello fr
0x0xbfcac46c: 6f 6d 20 68 65 6c 6c 00 67 6f 74 20 70 74 72 3a om hell.got ptr:
0x0xbfcac47c: 20 25 70 20 73 69 7a 65 3a 20 25 64 0a 00 00 00 %p size: %d....
0x0xbfcac48c: 73 74 72 75 63 74 20 76 61 6c 75 65 20 74 65 73 struct value tes

Buffer is smaller:

# ./a.out
struct value test, sizeof(char*): 4 sizeof(int): 4
mybuf ptr: 0xbfb3f25c
0x0x8049e20: 66 6f 6f 3d 5c f2 b3 bf 10 00 00 00 62 61 72 3d foo=\.....bar=
0x0x8049e30: 10 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 ....LaTeLee=5202
0x0x8049e40: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x8049e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
got ptr: 0xbfb3f25c size: 16
0x0x8049e20: 66 6f 6f 3d 5c f2 b3 bf 10 00 00 00 62 61 72 3d foo=\.....bar=
0x0x8049e30: 10 00 00 00 4c 61 54 65 4c 65 65 3d 35 32 30 32 ....LaTeLee=5202
0x0x8049e40: 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50............
0x0x8049e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............
out mybuf [this is hello fr]
0x0xbfb3f25c: 74 68 69 73 20 69 73 20 68 65 6c 6c 6f 20 66 72 this is hello fr
0x0xbfb3f26c: 10 00 00 00 30 8a 04 08 00 00 00 00 f8 f2 b3 bf ....0.....
0x0xbfb3f27c: 46 9e 53 b7 01 00 00 00 24 f3 b3 bf 2c f3 b3 bf F.S.....$...,...
0x0xbfb3f28c: c8 42 6a b7 21 38 7e b7 ff ff ff ff f4 bf 7e b7 .Bj.!8.....

illustrate:

The statement memcpy( & amp;bufptr, myptr->valFoo, sizeof(myptr->valFoo)); in the get_struct function can only run normally on 64-bit systems because When StructInfo_t defines the field size, it follows the maximum principle, that is, 8 bytes are used to store the pointer. In 32-bit systems, bufptr is only 4 bytes, so memcpy( & amp;bufptr, myptr->valFoo, sizeof(char*)); must be used to apply to systems with different digits. .

Summary

After testing, the solutions mentioned above can solve the problems encountered. But how effective it will be remains to be seen later.