Looking for a more elegant way to do memory offsets

M

mikegw

Hello all.

I am currently using an implementation of sysV shared memory. The entire
shared memory is allocated is one continuous block of which I get the
pointer to the head, everything should be done as offsets from this. At the
moment I have two data structures, a head to a linked list which in it
contains the pointer to the first element in the linked list( this is
redundant as far as I can work out) and the list itself. The data
structures are as follows

struct ipc_particle
{
int zone_id;
int zone[3];
int fur_flag;
double radiusR; //radius of repulsion (contact radius)
double radiusA; //radius of attraction (influence radius)
double mass; //mass
double poissons; //poissons ratio
double youngs; //Young's modulus
double zeta; //zeta potential
double force[3]; //force
double position[3]; //position psn[0]=x, psn[1]=y, psn[2]=z
double velocity[3]; //velocity

};

struct dem_mem
{
int particles;
int processors;
int run;
int time_semaphore;
double clock;
struct ipc_particle* particle_head;
};

to calculate the dem_mem->particle_head I currently use particle_head =
dem_mem_pointer+(sizeof(struct dem_mem))

to reference the elements in the linked list I just use
particle_head[offset].zone_id for example.

I don't like how I calculate the particle_head, for a start I get a warning
about adding an int to a pointer.

Basically I know that my first element is sizeof(struct dem_mem) away from
the header pointer. Is there a better way to get this?

Thanks and I hope my rambling made sense.

Mike
 
G

Grumble

mikegw said:
I don't like how I calculate the particle_head, for a start I get a
warning about adding an int to a pointer.

Basically I know that my first element is sizeof(struct dem_mem)
away from the header pointer. Is there a better way to get this?

Thanks and I hope my rambling made sense.

I'm not sure I understand your problem, so please forgive me if I've
missed your point.

Could you use the offsetof() macro defined in stddef.h?

http://www.opengroup.org/onlinepubs/009695399/basedefs/stddef.h.html
 
C

Chris Torek

I am currently using an implementation of sysV shared memory.

The underlying shared-memory implementation is off-topic, but
this is an issue in a "general C" sense, in one important way:
The entire shared memory is allocated is one continuous block
of which I get the pointer to the head, everything should be done
as offsets from this.

There is a way to restate this without pulling in shared-memory
issues, and it goes like this:

"I have a large block of special, but otherwise undifferentiated,
C-bytes, and I need to write a general-purpose allocator, much
like malloc(), that works within this block."

Unfortunately, the Standard C answer is "you cannot write a malloc()".
The malloc() function returns memory that is "suitably aligned"
for any data type, and Standard C does not give you -- where "you"
means "anyone other than the implementor writing malloc() in the
first place" -- the tools needed to discover this alignment.

In your case, though, you have a fighting chance, because you do
not have to write a fully-general malloc(). Instead, you can
simply collect up all the types you actually use, inside these
data structures in this special block of memory, and write an
allocator that only aligns suitably for these types.

(Or you can even just sleaze out entirely and assume that sizeof(double)
is the maximum required alignment, that the block is already aligned
for use as "double", and that your two structures, since they both
contain "double", are also so aligned. :) )
At the moment I have two data structures, a head to a linked list
which in it contains the pointer to the first element in the linked
list (this is redundant as far as I can work out) and the list
itself.

The data structures you show here are not linked-lists.
The data structures are as follows

struct ipc_particle
{
int zone_id;
int zone[3];
int fur_flag;
double radiusR; //radius of repulsion (contact radius)
double radiusA; //radius of attraction (influence radius)
double mass; //mass
double poissons; //poissons ratio
double youngs; //Young's modulus
double zeta; //zeta potential
double force[3]; //force
double position[3]; //position psn[0]=x, psn[1]=y, psn[2]=z
double velocity[3]; //velocity

};

In particular, an "ipc_particle" structure does not contain a
pointer to another "ipc_particle", so it cannot be a list. That
leaves:
struct dem_mem
{
int particles;
int processors;
int run;
int time_semaphore;
double clock;
struct ipc_particle* particle_head;
};

and here a "struct dem_mem" does not contain a pointer to another
"dem_mem", so it cannot be a list either.
to calculate the dem_mem->particle_head I currently use particle_head =
dem_mem_pointer+(sizeof(struct dem_mem))

If "dem_mem_pointer" has type "char *", this is likely to work.

If "dem_mem_pointer" has type "struct dem_mem *", this is still
likely to work, but wastes enormous amounts of space -- you just
want to add 1, not something like 32 or so. You want to "move
forward" in your block-of-bytes by 1 "struct dem_mem" object, and
pointer arithmetic works in units of the pointed-to objects.
to reference the elements in the linked list I just use
particle_head[offset].zone_id for example.

This is not a linked-list access, but rather an array access:
a "struct dem_mem"'s particle_head points to the first element
of an array (of unspecified size) of "struct ipc_particle"s,
and you move forward in memory by "offset" units of that size:

+-----------------+
| particles |
| processors |
: ... :
| particle_head --|---------\
+-----------------+ |
|
|
/-----------------------------/
|
_\|+-----------------------...
| zone_id | zone_id |
| zone | zone |
| fur_flag | fur_flag |
: : :
| velocity | velocity |
+-----------------------...

Given that "particle_head" points to the first element (subscript
0) of the array, particle_head[0] names that entire array element
-- the whole structure, with fields like "zone_id". particle_head[1]
names the entire array element "one further along" in memory,
particle_head[2] names the entire element "two further along", and
so forth.

This is the very same pointer arithmetic, stepping along by units
of the thing pointed-to, that you get if you add 1 to a "struct
dem_mem". The only difference is that the size of the target of
a "dem_mem" pointer has no defined relationship to the size of the
target of an "ipc_particle" pointer. The distance (measured in
bytes) that "+ 1" moves, changes!
I don't like how I calculate the particle_head, for a start I get a warning
about adding an int to a pointer.

Adding an int to a pointer is fine -- this is how subscripting
works in C. The problem lies elsewhere.
Basically I know that my first element is sizeof(struct dem_mem) away from
the header pointer. Is there a better way to get this?

If you have a C99 compiler, you can replace the entire technique
with a "flexible array member", where "struct dem_mem" ends with
an unspecified number of "struct ipc_particle"s:

struct ipc_particle { ... as before ... };

struct dem_mem {
... as before, but ending with ...
struct ipc_particle particles[];
};

Now the only thing you need to your malloc()-like allocator to
handle is the "struct dem_mem" itself. See the comp.lang.c FAQ
for details on C99 flexible array members, and ways to fake them
in C89. (Given that you already depend on shared-memory, depending
on things not officially valid in C89, such as faked flexible array
members, is probably not going to cause additional portabiility
problems.)
 
M

mikegw

I am reposting as my newsserver is useless. I have changed some code so I
have edited to realise this.

Hello all.

I am currently using an implementation of sysV shared memory. The entire
shared memory is allocated is one continuous block of which I get a pointer
to the head, I can do what ever I want WITHIN the confines of this block.
At the moment I have two data structures, ipc_particle and dem_mem.

struct ipc_particle
{
int zone_id;
int zone[3];
int fur_flag;
double radiusR; //radius of repulsion (contact radius)
double radiusA; //radius of attraction (influence radius)
double mass; //mass
double poissons; //poissons ratio
double youngs; //Young's modulus
double zeta; //zeta potential
double force[3]; //force
double position[3]; //position psn[0]=x, psn[1]=y, psn[2]=z
double velocity[3]; //velocity
};

struct dem_mem
{
int particles;
int processors;
int run;
int time_semaphore;
double clock;
};

Currently I am having difficulty navigating the structure. It is trivial to
place a single dem_mem on the head of the memory, a second dem_mem would
also be easy as I would only have to derefernce it as dem_mem_array[1]
(where struct dem_mem* dem_mem_array). However I would like to have the
second and up to n elements to be of type ipc_particle. so my memory would
look like
|dem_mem|ipc_particle|ipc_particle|ipc_particle|

as said I can get a pointer to the head of my shared memory easily, the
wrinkle is calculating the offset from the head to the first ipc_particle
element.

My current attempt looks like this

struct ipc_particle* cursor;
struct dem_mem head;

blah blah blah

cursor = head+(sizeof(struct dem_mem));

Now I know this does not work.

What will?

Thanks

Mike
 
B

Barry Schwarz

I am reposting as my newsserver is useless. I have changed some code so I
have edited to realise this.

Hello all.

I am currently using an implementation of sysV shared memory. The entire
shared memory is allocated is one continuous block of which I get a pointer
to the head, I can do what ever I want WITHIN the confines of this block.
At the moment I have two data structures, ipc_particle and dem_mem.

struct ipc_particle
{
int zone_id;
int zone[3];
int fur_flag;
double radiusR; //radius of repulsion (contact radius)
double radiusA; //radius of attraction (influence radius)
double mass; //mass
double poissons; //poissons ratio
double youngs; //Young's modulus
double zeta; //zeta potential
double force[3]; //force
double position[3]; //position psn[0]=x, psn[1]=y, psn[2]=z
double velocity[3]; //velocity
};

struct dem_mem
{
int particles;
int processors;
int run;
int time_semaphore;
double clock;
};

Currently I am having difficulty navigating the structure. It is trivial to
place a single dem_mem on the head of the memory, a second dem_mem would
also be easy as I would only have to derefernce it as dem_mem_array[1]
(where struct dem_mem* dem_mem_array). However I would like to have the
second and up to n elements to be of type ipc_particle. so my memory would
look like
|dem_mem|ipc_particle|ipc_particle|ipc_particle|

as said I can get a pointer to the head of my shared memory easily, the
wrinkle is calculating the offset from the head to the first ipc_particle
element.

My current attempt looks like this

struct ipc_particle* cursor;
struct dem_mem head;

blah blah blah

cursor = head+(sizeof(struct dem_mem));

Now I know this does not work.

What will?

This doesn't work because, when you do pointer arithmetic, C
automatically takes the size of the object being pointed to into
account. You can make the arithmetic come out correctly with
cursor = (ipc_particle*)((char*)head + sizeof(struct dem_mem));
or the simpler
cursor = (ipc_particle*)(head+1);
which is also equivalent to
cursor = (ipc_particle*)&head[1];
but this may not solve the problem due to alignment issues.

If the sizeof(struct ipc_particle) is a suitable alignment for it and
if your system has an integer type to and from which you can convert
pointers, then you can insure that the value in cursor is properly
aligned with something like:

long pointer_integer; /* long is just a common example of a
possible integer type that meets the above criteria */
pointer_integer = (int)(head+1);
pointer_integer += sizeof(struct ipc_particle)-1;
pointer_integer /= sizeof(struct ipc_particle);
pointer_integer *= sizeof(struct ipc_particle);
cursor = (struct ipc_particle*) pointer_integer;


<<Remove the del for email>>
 
N

Nick Keighley

I am currently using an implementation of sysV shared memory. The entire
shared memory is allocated is one continuous block of which I get a pointer
to the head, I can do what ever I want WITHIN the confines of this block.
At the moment I have two data structures, ipc_particle and dem_mem.

struct ipc_particle
{
<snip

};

struct dem_mem
{

};

Currently I am having difficulty navigating the structure. It is trivial to
place a single dem_mem on the head of the memory, a second dem_mem would
also be easy as I would only have to derefernce it as dem_mem_array[1]
(where struct dem_mem* dem_mem_array). However I would like to have the
second and up to n elements to be of type ipc_particle. so my memory would
look like
|dem_mem|ipc_particle|ipc_particle|ipc_particle|

I may have misunderstood but how about inventing a structure that
reflects what the shared memory should look like.

struct Memory_layout
{
struct dem_mem dm;
struct ipc_paricle [3];
};

void *shm_p; /* somehow points to shared memory */
/* I assume the OS has dealt with alignment
problems */

struct Memory_layout *my_shm;

my_shm = (struct Memory_layout*)shm_p;

my_shm->ipc_particle [1].fred = joe;

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,246
Members
46,839
Latest member
MartinaBur

Latest Threads

Top