Programming Techniques
|
4.8) Enhancing struct Compatibility
|
Even with the best design planning, it's often necessary to add new variables to existing
data structures to support new features or capabilities in your program.
Data structure extensibility becomes an issue, however, unless all the components
for creating and accessing the data are kept exactly in sync.
Struct "versioning" problems may occur in many common situations:
The data structure is written as part of a file that is stored on disk
and read back later for processing (potentially by a new version of the program).
The structure is used to store information that is part of a data transfer
that is passed electronically for processing by another machine (potentially using
a newer or different version of the program).
Portions of the the application are compiled and linked at different times (such
as DLL's and COM modules).
Whenever components of an application, utility or shared library are built as
separate parts, the risk for data structure version incompatibility arises.
This is becoming even more prevalent today as as information is passed through
networks or over the Internet for processing by a remote server.
The following guidelines are designed to enhance structures to promote extensibility
and upward compatibility.
Include a structSize Member In Structures
Often with functions that are built into dynamically linked libraries (DLL's)
it may be necessary later to update a function which, in turn, may require
adding additional items to a structure that is passed by pointer reference.
Version problems will occur if an existing application passes a pointer of an
old structure type to a function in a new DLL with an updated structure type.
To simplify updates and to facilitate DLL compatibility between versions,
unless you are absolutely certain that a structure will never change,
include an "INT32 structSize" variable as the first data
member of all structures.
By examining the structSize variable, updated functions can
determine specifically which version of a structure is being passed, and then act
accordingly in a compatible manner.
The _InitStruct() macro is a convenient method to initialize
a structure to zero and then automatically set the structSize
member (see the
Metagraphics C/C++ Programming Guidelines manual for more information
on _InitStruct()).
The application code would be something like this:
typedef struct _fooStruct
{
INT32 structSize; /* size of this structure */
/* other structure members defined here */
} fooStruct;
_InitStruct( &myStruct ); /* zeros the structure and sets structSize */
/* set other structure members */
foo( &myStruct ); /* call a function passing a pointer to the struct */
|
The called function code can now distinguish between different structure versions:
typedef struct _FOOSTRUCT_REV1 /* old version of FOOSTRUCT */
{
INT32 structSize; /* size of this structure */
/* other structure members defined here */
} FOOSTRUCT_REV1;
typedef struct _FOOSTRUCT /* current version of FOOSTRUCT */
{
INT32 structSize; /* size of this structure */
/* original structure members defined here */
/* new structure members defined here */
} FOOSTRUCT;
void foo( FOOSTRUCT *fooStruct )
{
if ( fooStruct->structSize == sizeof(FOOSTRUCT_REV1) )
{
/* cast fooStruct to FOOSTRUCT_REV1 and process accordingly */
}
else if ( fooStruct->structSize == sizeof(FOOSTRUCT) )
{
/* process fooStruct with current FOOSTRUCT definition */
}
else
{ /* We can also double check we are getting passed a valid parameter. */
/* Something is bad if FOOSTRUCT doesn't match any size we expect! */
_ASSERT( FALSE ); /* debug trap */
}
} /* foo() */
|
A structSize variable automates the older technique
of having a manually updated version number at the beginning of a data structure.
Include a structSize Parameter
For Functions Returning Structure Data
With a structSize variable as the first
element in a structure, when a function is called passing the structure as input the
called function can now easily identify a specific structure version (see above).
Returning data in a structure passed by pointer reference can also create
potential versioning problems.
If only a pointer to an empty structure is passed, the called function can only assume
its size and version.
If the caller's structure version is out of date and too small, data overwrite errors
can easily occur.
To enhance compatibility for structures passed by pointer for returning data,
include a structSize parameter along with the structure
pointer parameter passed to the function.
The structSize parameter allows the called function to
identify specifically which version of a structure is being passed, and then
act accordingly in a compatible manner.
FOO myFoo; /* FOO object instance handle */
FOOINFO myFooInfo; /* FOOINFO data structure */
MRESULT result; /* function return code */
/* create a FOO instance (foo instance handle is returned) */
result = Foo_Create( &myFoo );
_ASSERT( SUCCEEDED(result) );
/* get FOOINFO struct data */
result = Foo_GetFooInfo( myFoo, sizeof(FOOINFO), &myFooInfo );
_ASSERT( SUCCEEDED(result) );
|
By explicitly passing the size of the structure, the called function can now
distinguish between different structure versions:
/* Return FOOINFO structure data */
MRESULT Foo_GetFooInfo(
FOO foo, /* input, foo handle */
int fooInfoSize, /* input, fooInfo struct size */
FOOINFO *fooInfo ); /* output, fooInfo information */
{
if ( fooInfoSize == sizeof(FOOINFO_REV1) )
{
/* cast fooInfo to old FOOINFO_REV1 and process accordingly */
}
else if ( fooInfoSize == sizeof(FOOINFO) )
{
/* process fooInfo with current FOOINFO definition */
}
else
{ /* We can also double check we are getting passed a valid parameter. */
/* Something is bad if fooInfoSize doesn't match any size we expect! */
_ASSERT( FALSE ); /* debug trap */
}
} /* Foo_GetFooInfo() */
|
The preceding was excerpted from
Metagraphics C/C++ Programming Guidelines manual,
developed internally as part of our on-going efforts to improve the quality of our
software products.
Implementing a written corporate programming standards document is one of the first
steps in the
Capability Maturity Model for Software process (CMM-SW).
For additional information on CMM-SW visit the Carnegie Mellon University,
Software Engineering Institute web site at:
http://www.sei.cmu.edu/cmm/cmm.html
To Metagraphics Home Page http://www.metagraphics.com
© Copyright 1999 - Metagraphics Software Corporation. All rights reserved.
|