Protecting Structures in Embedded C

    Follow and star our public account for exciting content









Are you confused by the implementation of macros or their usage? The essence of the mask structure macro is to use a mask array chMask to protect the structure.
You can refer to the PLOOC usage examples from senior developers and its object-oriented programming based on C language in the document "Silly Child.pdf" (reply with: Object-oriented programming based on C language in our public account chat interface) to understand it better:
https://github.com/GorgonMeducer/PLOOC
Similarly, you can also look at the way to protect structures using incomplete types, which I have shared before. I will share that here as well.
In C language, using incomplete types to protect structures mainly involves not providing the complete definition when declaring the structure, and only providing the complete definition when needed (e.g., in its source file). The advantages and disadvantages of this method are:
Advantages:
Enhanced encapsulation: Using incomplete types can hide the internal details of the structure to some extent, preventing external code from directly accessing the members of the structure, thus improving the encapsulation and safety of the code.
Decoupling between modules: By declaring incomplete types, you can pass pointers to structures between multiple modules without exposing the complete definition of the structure. This helps reduce the coupling between modules, making the system more flexible and easier to maintain.
Disadvantages:
Usage limitations: Incomplete types have some limitations, such as not being able to directly use the sizeof operator to get the size of the incomplete type (because the compiler does not know its complete definition). This may make it impossible to use incomplete types when the size of the structure is needed.
Prone to errors: If the complete definition of an incomplete type is not provided correctly, or if inconsistent definitions are provided in multiple places, it may lead to compilation errors or runtime errors.
What are incomplete types? In C/C++, there are three different forms of incomplete types: void, arrays of unspecified length, and structures and unions with unspecified content. Using pointers or references to incomplete types does not require knowing all the contents of the type. For example:
We often declare arrays as follows:
extern int array[]; At this point, array is an incomplete type array. Generally, such array declarations are placed in the .h file, while the definition is in the .c file, where the specific length of the array is provided. If the length of the array needs to be changed later, it can be done directly in the .c file, and the external .h file remains unchanged.
Using arrays to explain may still be a bit hard to understand, so let's take a structure as an example.
Before that, let's consider a question: should we define the structure entity in the header file or in the source file?
In fact, it can be defined in either the header file or the source file.
Now, let's take an example of managing a dynamic array to demonstrate.
A dynamic array is relative to a static array. The length of a static array is predefined and cannot be changed once the size is given throughout the program. In contrast, a dynamic array can be resized according to the program's needs.
The memory space of a dynamic array is allocated from the heap (i.e., dynamically allocated). It is allocated when executing the code. Memory allocation occurs when the program reaches these statements. The programmer is responsible for releasing the memory. The advantage of using dynamic arrays is that they can effectively utilize storage space according to user needs.
(1) Structure entity defined in the header file For example, our demo has the following three files:
At this point, the content of dynamic_array.h is as follows:
We have created some interface functions to operate on the DA object, and we hope others can use these interfaces to manipulate data. Generally, when using code written by others, we also prioritize finding the relevant header files and then calling the external interface functions provided in those header files.
However, from this header file, we not only see some external interfaces but also the structure entity. Thus, some people might write code like this:
While there are interfaces available, some people prefer to manipulate data directly, which is a practice that is prone to errors. Moreover, the caller has a strong justification for pushing the blame: you exposed the data to me, why can't I manipulate your data directly? I just don't like using your provided interface, so what...
So the provider of dynamic_array.h still has to take the blame.
(2) Structure entity defined in the source file To avoid being blamed, we change our header file to:
At this point, the structure type dynamic_array_def is an incomplete type.
We move the structure entity definition to the source file, and now the caller cannot see what data is in dynamic_array_def, thus indirectly forcing the caller to use the interfaces we provide. If a problem arises, we are also willing to take the blame and investigate the issue.
Finally, here is the complete code for this demo project for those who need it:
dynamic_array.h:/* Public Account: Embedded Miscellaneous */
#ifndef __DYNAMIC_ARRAY_H
#define __DYNAMIC_ARRAY_H

/* Structure "renaming" */
typedef struct dynamic_array dynamic_array_def;

/* Initialize dynamic_array */
dynamic_array_def *DA_Init(void);

/* Destroy dynamic_array */
void DA_Clean(dynamic_array_def *pThis);

/* Set dynamic_array length */
void DA_SetSize(dynamic_array_def *pThis, unsigned len);

/* Get dynamic_array length */
unsigned DA_GetSize(dynamic_array_def *pThis);

/* Set value of a certain element in dynamic_array */
int DA_SetValue(dynamic_array_def *pThis, unsigned index, int value);

/* Get value of a certain element in dynamic_array */
int DA_GetValue(dynamic_array_def *pThis, unsigned index, int *pValue);

#endif dynamic_array.c:/* Public Account: Embedded Miscellaneous */
#include "dynamic_array.h"
#include 

/* Create a dynamic array structure template */
struct dynamic_array
{
int *array;
unsigned len;
};

/* Initialize dynamic_array */
dynamic_array_def *DA_Init(void)
{
    dynamic_array_def *pArray = malloc(sizeof(dynamic_array_def));

    pArray->array = NULL;
    pArray->len = 0;
}

/* Destroy dynamic_array */
void DA_Clean(dynamic_array_def *pThis)
{
free(pThis->array);
    pThis->len = 0;
free(pThis);
}

/* Set dynamic_array length */
void DA_SetSize(dynamic_array_def *pThis, size_t len)
{
    pThis->len = len;
    pThis->array = (int *) realloc(pThis->array, pThis->len * sizeof(int));
}

/* Get dynamic_array length */
size_t DA_GetSize(dynamic_array_def *pThis)
{
return pThis->len;
}

/* Set value of a certain element in dynamic_array */
int DA_SetValue(dynamic_array_def *pThis, size_t index, int value)
{
if (index > pThis->len)
{
return -1;
}

    pThis->array[index] = value;
return 0;
}

/* Get value of a certain element in dynamic_array */
int DA_GetValue(dynamic_array_def *pThis, size_t index, int *pValue)
{
if (index > pThis->len)
{
return -1;
}

*pValue = pThis->array[index];
return 0;
} main.c/* Public Account: Embedded Miscellaneous */
#include 
#include 
#include "dynamic_array.h"

int main(void)
{
int arr_elem = 0;

/* Initialize a dynamic array */
    dynamic_array_def *pArray = DA_Init();

/* Set array length to 10 */
    DA_SetSize(pArray, 10);

/* Assign values to array elements */
for (int i = 0; i < 10; i++)
{
        DA_SetValue(pArray, i, i);
}

/* Traverse array elements and print */
for (int i = 0; i < 10; i++)
{
        DA_GetValue(pArray, i, &arr_elem);
printf("%d ", arr_elem);
}

/* Clean up array */
    DA_Clean(pArray);

return 0;
} Compile and run:



Copyright Statement: This article is sourced from the internet, free to convey knowledge, copyright belongs to the original author. If there are any copyright issues, please contact me for deletion.

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

Follow my public account and reply "Planet" to join the knowledge planet, where all questions will be answered.


Click "Read the original" to see the details of the knowledge planet, feel free to share, collect, like, and view.


Leave a Comment

Your email address will not be published. Required fields are marked *