views:

120

answers:

3

Supposed that for some reason you are only allowed to use static memory in a C program. I have a basic structure that I am using in several places defined as below:

#define SMALL_STUFF_MAX_SIZE 64

typedef struct {
    /* Various fields would go here */
    ...
    double data[SMALL_STUFF_MAX_SIZE]; /* array to hold some data */
} SmallStuff;

Now, I have been asked to add a new feature that lead to a particular case where I need the same structure but with a much larger array. I can't afford to max up the array of the SmallStuff structure as memory is too tight. So I made a special version of the struct defined as below that I eventually cast to a (SmallStuff*) when calling functions that expect a pointer to a SmallStuff structure (the actual size of 'data' is properly handled in these functions)

#define BIG_STUFF_MAX_SIZE 1000000
typedef struct {
    /* Various fields, identical to the ones in SmallStuff would go here */
    ...
    double data[BIG_STUFF_MAX_SIZE]; /* array to hold some data */
} BigStuff;

Obviously, the proper way to do it would be to dynamically allocate the memory but as said above I can't use dynamic memory allocation.

Are there any side-effects that I should consider? Or better ways to deal with this kind of problem?

Thanks in advance.

A: 

Although its ugly code because of the complexity, there should not be any runtime problems because the sizes are hard-coded.

A better way to deal with it is to have algorithms which didnt need you to have 2 separate structs which only differ by size. However, I dont know your application, so you know best how to deal with this problem.

Andrew Keith
While I agree with your conclusions, I don't understand how you got them. "Because the sizes are hard-coded"? What does that have to do with casting between the two?
Chris Lutz
You are right, it's definitely ugly code which is why I am curious to know if there is a better way. Also, I don't think that making a different set of functions that expect pointers to BigStuff in order to avoid casting is any better...
Kenji Baheux
+3  A: 

What you're doing is fine, though it tends to scare people who are uncomfortable with pointers and casting.

The general solution for your problem is to get rid of BigStuff and SmallStuff and make a single Stuff structure with a size member and a double *data that points to an array of your choosing, instead of risking potential miscasts in your code later or having to change your functions when you discover you also need MediumStuff. This gives you the flexibility of using whatever sizes are appropriate.

typedef struct
{
  // the usual

  size_t data_length;
  double *data;
} Stuff;


double bigdata[BIG_STUFF_MAX_SIZE];
Stuff big = { ..., BIG_STUFF_MAX_SIZE, bigdata };
Variable Length Coder
Where is dynamic memory allocation used in my response? bigdata and big can be in global or function scope.
Variable Length Coder
I don't see any dynamic memory allocation either. However, this kind of move some internal bits of the structure and additional burden to the client side (in this case, the structure is used to implement a FIFO and the data field is not supposed to be directly accessed by the client). I guess that any solution has its own set of trade-offs... Thanks!
Kenji Baheux
I retract my initial complaint. This still creates scoping issues that can't be cleanly resolved without dynamic allocation.
Chris Lutz
Could you elaborate on the scoping issues?
Kenji Baheux
The scoping issues for the array are no more and no less than the scoping issues applying to the `struct` object itself, which are already extant. Ie, if the `struct` already has the proper lifetime, then it shouldn't be an issue for the array either - just allocate it in the same scope.
caf
+1  A: 
typedef struct {
    /* Various fields would go here */
    double data[]; /* a flexible array (C99 extension) */
} AnySizeStuff;

typedef struct {
  AnySizeStuff header;
  double smalldata[SMALL_STUFF_MAX_SIZE];
} SmallStuff;

typedef struct {
  AnySizeStuff header;
  double bigdata[BIG_STUFF_MAX_SIZE];
} BigStuff;

Then if x is either a SmallStuff or BigStuff, you can pass &x.header to routines that can take either.

Keith Randall
According to a page from IBM's documentation, it doesn't look like this can be done: "Any structure containing a flexible array member cannot be a member of another structure or array." What gives? http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/strct.htm#flexibleOn a side note, I am not allowed to use C99 extensions either...
Kenji Baheux
You're right, technically not allowed by the standard. But if you look farther down the page:For compatibility with GNU C, XL C/C++ extends Standard C and C++, to ease the restrictions on flexible arrays and allow the following: ... Structures containing flexible array members can be members of other structures.
Keith Randall