473,769 Members | 2,019 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Variable structure, constant length allocations

I'm working on a data structure that began life as a skip list
derivative, but has evolved to the point that it now only has a
passing resemblance to them. Each node of this structure has a
few constant size variables (ints and the like), an array holding
the actual data (chars in this case) and a random number of pointers
to other nodes in the structure.

At the moment my code uses a fixed size array for the contents
(which may or may not be filled) and the call to malloc for each
node is adjusted to allow for the number of the pointers in the
node. Nothing too special there.

However, I am using a _lot_ of these structures and a significant
proportion have comparatively short average lifetimes. With the
expection of a few configuration tables that rarely, if ever, change
once initialised they are my app's only dynamically allocated memory
and I'm slightly concerned about memory fragmentation because they
are of differing lengths. Simply allocating the maximum amount of
memory that could be needed is an unacceptable waste of memory
since the balance is skewed strongly towards low numbers of pointers
- 50% have only a single pointer, 25% two pointers, 12.5% three
and so on up to a maximum of about 25 pointers.

It occurs to me that it is possible to define a fixed sized structure
with a variable number of pointer if the length of the character
length varies in inverse proportion to the number of pointers.
The question is how to do it cleanly. Unions are out of the question
because the number of possible structure types. I considered having
the character buffer start at the same point as the second pointer
and computing the real start of the buffer as needed. However, I
am now leaning towards defining the character array as a maximum
buffer size and having a single pointer array at the end. That
is:

struct structure {
char buffer[MAX_BUFFER_LEN];
struct structure *ptr[1];
};

and using _negative_ array indices to store the extra pointers. I
can easily determine how many pointers are expected algorithmically
- it is something I need to keep track of in any case - and define
a macro to calculate the buffer's real maximum length when it is
needed (not very often). This should work fine but I can't help
feeling it seems a little messy. Does anyone have any better
solutions, or even any views on whether this is worth bothering
about?

--
Andrew Smallshaw
an*****@sdf.lon estar.org
Nov 10 '08 #1
8 3252
Andrew Smallshaw wrote:
....
It occurs to me that it is possible to define a fixed sized structure
with a variable number of pointer if the length of the character
length varies in inverse proportion to the number of pointers.
The question is how to do it cleanly. Unions are out of the question
because the number of possible structure types. I considered having
the character buffer start at the same point as the second pointer
and computing the real start of the buffer as needed. However, I
am now leaning towards defining the character array as a maximum
buffer size and having a single pointer array at the end. That
is:

struct structure {
char buffer[MAX_BUFFER_LEN];
struct structure *ptr[1];
};

and using _negative_ array indices to store the extra pointers.
Negative array indices are a constraint violation. It might work on
some systems, but it's not going to be portable. One safer approach
would be to simply store an array of 25 pointers in your structure, or
MAX_BUFFER_LEN/sizeof(struct structure *), whichever is larger. Insert
new pointers starting from the top of the array and working toward the
bottom, while accessing the unused bytes for use as your buffer at the
bottom by treating the entire structure as an array of char. It's
tricky and dangerous, I certainly would prefer a method that was
safer, even at the expense of a little extra space. You have to be
very careful to avoid overlap between the portion used for pointers
and the portion used for your buffer. However, if done right, it would
not violate any constraints and would have defined behavior.
Nov 10 '08 #2
jameskuyper said:

<snip>
Negative array indices are a constraint violation.
Which constraint do they violate?

<snip>

--
Richard Heathfield <http://www.cpax.org.uk >
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 10 '08 #3
Andrew Smallshaw wrote:
[...]
It occurs to me that it is possible to define a fixed sized structure
with a variable number of pointer if the length of the character
length varies in inverse proportion to the number of pointers.
The question is how to do it cleanly. Unions are out of the question
because the number of possible structure types. I considered having
the character buffer start at the same point as the second pointer
and computing the real start of the buffer as needed. However, I
am now leaning towards defining the character array as a maximum
buffer size and having a single pointer array at the end. That
is:

struct structure {
char buffer[MAX_BUFFER_LEN];
struct structure *ptr[1];
};

and using _negative_ array indices to store the extra pointers. I
can easily determine how many pointers are expected algorithmically
- it is something I need to keep track of in any case - and define
a macro to calculate the buffer's real maximum length when it is
needed (not very often). This should work fine but I can't help
feeling it seems a little messy. Does anyone have any better
solutions, or even any views on whether this is worth bothering
about?
A cleaner approach might use a union instead of a struct:

union onion {
char buffer[MAX_BUFFER_LEN];
union onion *ptr[
(MAX_BUFFER_LEN + sizeof(union onion*) - 1)
/ sizeof(union onion*)];
};

(The ugly arithmetic could be beautified by defining MAX_BUFFER_LEN
as a multiple of sizeof(union onion*).)

Another possibility is to store the characters just after the
struct itself, possibly with a convenient pointer to them in the
fixed portion of the struct. This snippet uses "the struct hack;"
you could also use C99's flexible array member:

struct structure {
char *buffer;
int this;
double that;
struct structure *ptr[1];
} *p;
p = malloc(offsetof (struct structure, ptr)
+ POINTER_CENSUS * sizeof(struct structure*)
+ strlen(the_stri ng) + 1);
if (p == NULL) ...
p->buffer = (char*)p
+ offsetof(struct structure, ptr)
+ POINTER_CENSUS * sizeof(struct structure*);
p->this = 42;
p->that = sqrt(42.0);
strcpy (p->buffer, the_string);

"Is it worth bothering about?" Dunno. If MAX_BUFFER_LEN is
small and the number of structs/unions is large, then maybe. If
MAX_BUFFER_LEN is large and/or the population is small, probably
not. You'll need to measure in the context of your own program.

--
Er*********@sun .com

Nov 10 '08 #4
Richard Heathfield wrote:
jameskuyper said:
....
Negative array indices are a constraint violation.

Which constraint do they violate?
Sorry - that was undefined behavior (6.5.6p8), not a constraint
violation.

I knew there was something wrong with that message, but I couldn't
figure out what. I've got to stop answering these questions too
quickly.
Nov 10 '08 #5
jameskuyper said:
Richard Heathfield wrote:
>jameskuyper said:
...
Negative array indices are a constraint violation.

Which constraint do they violate?

Sorry - that was undefined behavior (6.5.6p8), not a constraint
violation.
Note that, whilst negative array indices do indeed invoke undefined
behaviour, that doesn't mean that x[-1] is necessarily undefined. It isn't
the negative index that's the problem. The problem is that the underlying
pointer arithmetic ends up pointing before the beginning of the array. The
following code is well-defined:

int array[20];
void foo(void)
{
int *p = array + 10;
p[-5] = 42; /* linguistically: perfectly okay;
stylistically: vile
*/
}

--
Richard Heathfield <http://www.cpax.org.uk >
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 11 '08 #6
On Nov 10, 4:25*pm, Andrew Smallshaw <andr...@sdf.lo nestar.orgwrote :
I'm working on a data structure that began life as a skip list
derivative, but has evolved to the point that it now only has a
passing resemblance to them. *Each node of this structure has a
few constant size variables (ints and the like), an array holding
the actual data (chars in this case) and a random number of pointers
to other nodes in the structure.

At the moment my code uses a fixed size array for the contents
(which may or may not be filled) and the call to malloc for each
node is adjusted to allow for the number of the pointers in the
node. *Nothing too special there. *

However, I am using a _lot_ of these structures and a significant
proportion have comparatively short average lifetimes. *With the
expection of a few configuration tables that rarely, if ever, change
once initialised they are my app's only dynamically allocated memory
and I'm slightly concerned about memory fragmentation because they
are of differing lengths. *Simply allocating the maximum amount of
memory that could be needed is an unacceptable waste of memory
since the balance is skewed strongly towards low numbers of pointers
- 50% have only a single pointer, 25% two pointers, 12.5% three
and so on up to a maximum of about 25 pointers.

It occurs to me that it is possible to define a fixed sized structure
with a variable number of pointer if the length of the character
length varies in inverse proportion to the number of pointers.
The question is how to do it cleanly. *Unions are out of the question
because the number of possible structure types. *I considered having
the character buffer start at the same point as the second pointer
and computing the real start of the buffer as needed. *However, I
am now leaning towards defining the character array as a maximum
buffer size and having a single pointer array at the end. *That
is:

* *struct structure {
* * * char buffer[MAX_BUFFER_LEN];
* * * struct structure *ptr[1];
* *};

and using _negative_ array indices to store the extra pointers. *I
can easily determine how many pointers are expected algorithmically
- it is something I need to keep track of in any case - and define
a macro to calculate the buffer's real maximum length when it is
needed (not very often). *This should work fine but I can't help
feeling it seems a little messy. *Does anyone have any better
solutions, or even any views on whether this is worth bothering
about?
Suggest you try something simple first. Implement an allocator that
maintains N free lists for your N distinct possible node sizes. For
skip lists, N ought to be no more than 50 or so. Replenish these free
lists when empty by allocating standard-size blocks of a few pages (at
least) to contain a bunch of equal-sized nodes. Alloc and free are
now just a few instructions each to unchain and chain from the
respective free list. Average fragmentation can't exceed half a node
per block. If a given size goes dormant, its free list will be
swapped out. This costs little, but if it's still too much, you can
recycle blocks containing only free nodes: not hard to do with an
allocation counter stored in each block header.

Nov 11 '08 #7
On 2008-11-11, Richard Heathfield <rj*@see.sig.in validwrote:
>
Note that, whilst negative array indices do indeed invoke undefined
behaviour, that doesn't mean that x[-1] is necessarily undefined. It isn't
the negative index that's the problem. The problem is that the underlying
pointer arithmetic ends up pointing before the beginning of the array. The
following code is well-defined:
I was pretty sure that they were. I should be OK in this instance
though? Although this is a 'real' negative index going past the
beginning of an array, I know in advance it is going to clobber
another array and thus won't hit any undefined memory.

Of course, I'll have to be careful to respect the 'real' length of
the preceding array but looking at my code it is easily refactored
so that only comes up at one point. This code is going to be a
little on the messy side but I think all things considered it will
be an acceptable trade off.

--
Andrew Smallshaw
an*****@sdf.lon estar.org
Nov 11 '08 #8
Andrew Smallshaw wrote:
On 2008-11-11, Richard Heathfield <rj*@see.sig.in validwrote:
>Note that, whilst negative array indices do indeed invoke undefined
behaviour, that doesn't mean that x[-1] is necessarily undefined. It isn't
the negative index that's the problem. The problem is that the underlying
pointer arithmetic ends up pointing before the beginning of the array. The
following code is well-defined:

I was pretty sure that they were. I should be OK in this instance
though? ...
No.
... Although this is a 'real' negative index going past the
beginning of an array, I know in advance it is going to clobber
another array and thus won't hit any undefined memory.
The wording of the standard makes it legal for an implementation to
implement pointers in such a way as to enable run-time bounds checking.
That would be sufficient to make your program blow up. However,
implementations which do that by default are rare, possibly
non-existent, so you're extremely unlikely to run into a problem for
that reason.

A far more realistic worry is that, because access memory through
negative offsets from an array has undefined behavior, an implementation
is allowed to optimize code in ways that depend upon the assumption that
such accesses will never be attempted. Your code will presumably access
the same memory through ptr[i] for negative values of 'i', and also
through positive offsets from buffer[]. I presume that it will carefully
synchronize the two uses of that memory so that they don't interfere
with each other. However, all of that careful synchronization will be
wasted: an implementation can legally optimize your code to delay reads
or writes to that memory in ways that will mess up your careful
synchronization . Such optimizations are allowed, because you're not
supposed to access buffer[] through ptr[], and vice versa.

Nov 11 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
2751
by: BigDadyWeaver | last post by:
I am using the following code in asp to define a unique and unpredictable record ID in Access. <% 'GENERATE UNIQUE ID Function genguid() Dim Guid guid = server.createobject("scriptlet.typelib").guid guid=Left(guid,instr(guid,"}")) genguid=guid
16
1753
by: steflhermitte | last post by:
Dear cpp-ians, I am working with a structure: struct meta_segment { long double id; long double num; long double mean; bool done;
13
21376
by: HappyHippy | last post by:
Hi, I'm wondering what you think about this piece of code: #include<iostream> int main() { int size; std::cin >> size;
6
2070
by: JNY | last post by:
Hello, Is it possible to declare an array with variable indeces? i.e. int x = 4; int myArray; for (j = 0;j < 5;j++) {
3
1152
by: Alexander Arlievsky | last post by:
Hi, C# compiler issues error message on the following lines: GetStruct().Depth = 10; if GetStruct() returns structure (value type). It seems to be correct - else you will modify temporary value on the stack. It still allows to call method, so GetStruct().SetDepth(10) compiles perfectly, although obviosly still modifies only temporary value on the stack. But in our case "Depth" is property, and its "set" implementation modifies some...
2
1825
by: Avi Laviad | last post by:
hi, sorry for the dumb question but how do i code a bit variable in c? i mean - shoudlnt the synax need to be: bit j; j = 1; correct me if im wrong (and i suppose i am). Avi.
8
10167
by: redefined.horizons | last post by:
I would like to have an array declaration where the size of the array is dependent on a variable. Something like this: /* Store the desired size of the array in a variable named "array_size". */ unsigned short int array_size = 25; /*Declare an array named "numbers" using the variable initialized above. */ unsigned short int numbers;
3
2047
by: SRoubtsov | last post by:
Dear all, Do you know whether ANSI C (or some other dialects) support the following: * a variable name coincides with a type name, * a structure/union field name coincides with a type name in the same file (.c + all relevant .h's)? e.g.
7
2796
by: Cromulent | last post by:
In section 6.7.5.2 it states the following: If the size is not present, the array type is an incomplete type. If the size is*instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope;124) such arrays are nonetheless complete types. If the size is an integer constant expression and the element
0
9579
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, well explore What is ONU, What Is Router, ONU & Routers main usage, and What is the difference between ONU and Router. Lets take a closer look ! Part I. Meaning of...
0
9420
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10205
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9984
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9851
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
6662
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5441
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3556
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2811
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.