Populating Generated Structure Variables for Encoding

Prior to calling a compiler generated encode function, a variable of the type generated by the compiler must be populated. This is normally a straightforward procedure – just plug in the values to be encoded into the defined fields. However, things get more complicated when more complex, constructed structures are involved. These structures frequently contain pointer types which means memory management issues must be dealt with.

There are three alternatives for managing memory for these types:

  1. Allocate the variables on the stack and plug the address of the variables into the pointer fields,

  2. Use the standard malloc and free C functions or new and delete C++ operators to allocate memory to hold the data, and

  3. Use the rxtMemAlloc and rtxMemFree run-time library functions or their associated macros.

Allocating the variables on the stack is an easy way to get temporary memory and have it released when it is no longer being used. But one has to be careful when using additional functions to populate these types of variables. A common mistake is the storage of the addresses of automatic variables in the pointer fields of a passed-in structure. An example of this error is as follows (assume A, B, and C are other structured types):

   typedef struct {
      A* a;
      B* b;
      C* c;
   } Parent;

   void fillParent (Parent* parent)
   {
      A aa;
      B bb;
      C cc;

      /* logic to populate aa, bb, and cc */
      ...

      parent->a = &aa;
      parent->b = &bb;
      parent->c = &cc;
   }

   main ()
   {
      Parent parent;

      fillParent (&parent);

      encodeParent (&parent); /* error! pointers in parent
                                 reference memory that is
                                 out of scope */
      ...
   }

In this example, the automatic variables aa, bb, and cc go out of scope when the fillParent function exits. Yet the parent structure is still holding pointers to the now out of scope variables (this type of error is commonly known as “dangling pointers”).

Using the second technique (i.e., using C malloc and free) can solve this problem. In this case, the memory for each of the elements can be safely freed after the encode function is called. But the downside is that a free call must be made for each corresponding malloc call. For complex structures, remembering to do this can be difficult thus leading to problems with memory leaks.

The third technique uses the compiler run-time library memory management functions to allocate and free the memory. The main advantage of this technique as opposed to using C malloc and free is that all allocated memory can be freed with a single rtxMemFree call. The rtxMemAlloc macro can be used to allocate memory in much the same way as the C malloc function with the only difference being that a pointer to an initialized OSCTXT structure is passed in addition to the number of bytes to allocate. All allocated memory is tracked within the context structure so that when the rtxMemFree function is called, all memory is released at once.