473,811 Members | 2,597 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Offset/alignement of structure members

Hello,

I'm wondering about the portability and correctness of the
following scenario.

I have a generic doubly linked list structure, and it contains
generic nodes that look like this:

struct node
{
struct node *head;
struct node *tail;
};

struct list
{
struct node *first;
struct node *last;
};

Now, I want to use the generic list and node structures so that

- The list and its nodes stay completely generic.
That means I can have generic functions like

add_head(struct list *, struct node *);

Any list can be traversed and examined and manipulated
with the generic functions, as long as the operations
are stay on the generic level.

- The nodes can contain application specific data. That is:
the node structure is extended by adding application specific
fields, which can only be accessed if the application knows
what kind of node it is using.

Application specific node would look like

struct my_app_node
{
struct node node;
int datafield1;
char *datafield2;
etc.
};

Now, an application could do:

struct list mylist;
struct my_app_node node1;
struct my_app_node node2;

init_list(&myli st);

add_head(&mylis t, (struct node *)&node1);
add_head(&mylis t, (struct node *)&node2);

So, is this correct ISO C? Is this portable?

I know that I could do also:

add_head(&mylis t, &node1.node) ;
But, of course, both questions boil down to: can I trust
that offset of "node" inside my_app_node is 0? And also,
does the compiler let me get away with the cast?
I also do know that a certainly correct solution would be:

struct node
{
struct node *next;
struct node *prev;
void *data;
};

struct my_app_node
{
struct node node;
/* data fields follow */
};

struct my_app_node mynode;
mynode.node.dat a = &mynode;

But in this scenario I'm completely vasting one pointer.

(This all motivated by GCC 3.3's strict alignment stuff...)
Nov 13 '05 #1
3 5005
dis
"Arto Huusko" <ar*********@ut u.fi> wrote in message
news:pa******** *************** *****@utu.fi...
Hello,

I'm wondering about the portability and correctness of the
following scenario.

I have a generic doubly linked list structure, and it contains
generic nodes that look like this:

struct node
struct node *head;
struct node *tail;
};

struct list
{
struct node *first;
struct node *last;
};

Now, I want to use the generic list and node structures so that

- The list and its nodes stay completely generic.
That means I can have generic functions like

add_head(struct list *, struct node *);

Any list can be traversed and examined and manipulated
with the generic functions, as long as the operations
are stay on the generic level.

- The nodes can contain application specific data. That is:
the node structure is extended by adding application specific
fields, which can only be accessed if the application knows
what kind of node it is using.

Application specific node would look like

struct my_app_node
{
struct node node;
int datafield1;
char *datafield2;
etc.
};

Now, an application could do:

struct list mylist;
struct my_app_node node1;
struct my_app_node node2;

init_list(&myli st);

add_head(&mylis t, (struct node *)&node1);
add_head(&mylis t, (struct node *)&node2);

So, is this correct ISO C? Is this portable?
Yes, this code fragment is conforming.
I know that I could do also:

add_head(&mylis t, &node1.node) ;
But, of course, both questions boil down to: can I trust
that offset of "node" inside my_app_node is 0? And also,
does the compiler let me get away with the cast?


Yes, offsetof(struct my_app_node, node) is guaranteed to yield a value of 0.
The cast is necessary as a pointer to a structure object points to its
initial member after suitable conversion.

[snip]
Nov 13 '05 #2
Arto Huusko wrote:

I'm wondering about the portability and correctness of the
following scenario.

I have a generic doubly linked list structure, and it contains
generic nodes that look like this:

struct node
{
struct node *head;
struct node *tail;
};

struct list
{
struct node *first;
struct node *last;
};

Now, I want to use the generic list and node structures so that

- The list and its nodes stay completely generic.
That means I can have generic functions like

add_head(struct list *, struct node *);


You have to do two basic things. Have the data accessible by code
the application provides, because ONLY the application knows the
type of that data. Have the lists manipulated by code that
preserves those generic pointers, which have to be of type void*.
Thus your basic node will look something like:

struct node {
struct node *next;
struct node *prev;
void* dataptr;
}

This will NOT be in the published header file, which will only
contain:

typedef struct node *node;

keeping the definition totally hidden from the application. Now
your call will be something like:

add_head(node thelist, void *datum);

where thelist was created by the call:

node thelist = createlist();

and you will probably also want

void destroylist(nod e thelist, freedata destroydata);

where destroydata is a pointer to a routine receiving void* and
releasing the data it points to. This may be required for other
operations, and you might supply it once and for all via
createlist.

Now createlist can malloc a struct node, initialize the pointers
to null, or to point back to the head if desired, with a NULL
datum, and you can henceforce use that dummy node to hold the
first and last pointers.

An example is worth a good deal of rambling. You can see exactly
this sort of generic operation in hashlib.zip, especially noting
the example usages in wdfreq and markov. It can be found at:

<http://cbfalconer.home .att.net/download/>

--
Chuck F (cb********@yah oo.com) (cb********@wor ldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net> USE worldnet address!
Nov 13 '05 #3
CBFalconer wrote:

You have to do two basic things. Have the data accessible by code
the application provides, because ONLY the application knows the
type of that data. Have the lists manipulated by code that
preserves those generic pointers, which have to be of type void*.
Thus your basic node will look something like:

struct node {
struct node *next;
struct node *prev;
void* dataptr;
}
[...]


This approach works, and has some advantages. One is that
a given data item can exist simultaneously in an arbitrary
number of lists.

However, it also has a disadvantage: The linkage information
is split away from the "payload," and this gets you into issues
of allocating storage for the two independently, worrying about
all those tiny allocations of pared-down `struct node' objects,
and so on. All these issues are manageable, but they do require
some management -- and if you don't need the full flexibility
of CBF's method, the O.P.'s technique of embedding the links
in the same struct as the payload can be more convenient.

Back to the O.P.'s original question: In a situation like

struct node {
struct node *next;
struct node *prev;
};

struct data {
struct node links;
int payload[42];
double trouble[2];
};

.... is the `links' member of `struct data' guaranteed to be
at offset zero within the struct? Yes, says Section 6.7.2.1
paragraph 13: "A pointer to a structure object, suitably
converted, points to its initial member [...] and vice versa.
There may be unnamed padding within a structure object, but not
at its beginning." So you can safely feed a pointer to the
`links' member into your linked-list package, get that same
pointer back later on, and convert it into a `struct data*'
without trouble:

struct list mylist;
struct data mydata;
struct data *dptr;
...
add (&mylist, &mydata.link s);
...
dptr = (struct data*) get (&mylist);

In fact, you can do a little bit more without too much
trouble. Suppose you want each `struct data' to exist in
exactly two lists (or in any fixed number of lists). You can
still keep the linkage information with the payload:

struct data {
struct node links1;
struct node links2;
int payload[42];
double trouble[2];
};

The `links1' element is at offset zero, and can be handled as
before. The `links2' element is not at offset zero, but it is
at a constant offset, namely `offsetof(struc t data, links2)'.
You can insert the struct into a secondary list like

struct list list2;
struct data mydata;
...
add (&list2, &mydata.links2) ;

Later on when you want to retrieve it you must work a little
harder (the following is spelled out for clarity; in practice
you'd probably abbreviate things a bit):

struct list *lptr;
struct data *dptr;
...
lptr = get (&list2);
dptr = (struct data *)
( (char*)lptr - offsetof(struct data, links2) );

That is, you retrieve a pointer to a `links2' element (because
that's the sort of pointer you put into the list in the first
place), and then you "back up" by a known distance to find the
start of the `struct data' that contains it. Of course, you've
got to be careful not to mix `links1' and `links2' pointers in
the same list; this technique requires that you know what offset
to use.

For a small, fixed number of lists -- one is the commonest
case, sparse matrix representations sometimes use a "row" list
and a "column" list -- this technique can be recommended. It's
not good for a variable number of lists (because it's hard to
keep track of the proper offsets) or for a large number of lists
(because the bookkeeping gets unwieldy and the chance of error
grows); for those circumstances I'd prefer CBF's technique.

--
Er*********@sun .com
Nov 13 '05 #4

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

Similar topics

11
3480
by: Bradford Chamberlain | last post by:
I work a lot with multidimensional arrays of dynamic size in C, implementing them using a single-dimensional C array and the appropriate multipliers and offsets to index into it appropriately. I tend to iterate over subsets of these arrays by walking a pointer and an offset per dimension across their dimensions. I've found that this tends to result in more performance in a portable manner than doing explicit indexing calculations and...
13
7302
by: John | last post by:
In the course of an assignment, I learned the hard way that I shouldn't try to free a malloc'd member of a malloc'd structure after having freed that structure (i.e., free( structure ); free( structure->bufferspace ) ). My question is, if I free just the structure, will the (e.g.) bufferspace be freed implicitly, or do I have to (as I currently am) free the members first? Thanks. -cjl
15
2797
by: damian birchler | last post by:
Hi I'm wondering of what type a structure is. Of course, it is a _structure_, but an array isn't an _array_ either. So of what type is a structure? I'd say a pointer, am I right?
15
2719
by: junky_fellow | last post by:
I am trying to find the offset of a member "mbr" inside a structure "str" as follows: offset = &(struct str *)0->mbr; But, on compilation I get the following error: cc: Error: m1.c, line 55: In this statement, "0" has a signed int type, but occurs in a context that requires a pointer. (needpointer) Can anybody point out where the problem is ?
10
4067
by: junky_fellow | last post by:
I am trying to print the offset of a particulat member in a structure, but it's not working. I am using the following expression to print the offset. &(struct my_struct *)0->member_name What's wrong with this ? If I use, &((struct my_struct *)0)->member_name, it works. But it seems
1
2249
by: J | last post by:
I'm interfacing with a C api (via Interop) which uses the following typedef struct... typedef struct _columnflags { BYTE bNoUpdate : 1; BYTE bSetToNull : 1; BYTE bDefault : 1; } columnflags;
1
2247
by: Brad | last post by:
Using vb.net, I am attempting to copy a byte array buffer to a structure but need to specify an offset, in bytes, from the top of the structure. I have studied the Marshal class but it appears I can only specify the structure name...
19
8773
by: Rahul | last post by:
Hi, Is there a way to find the offset of a class member at compile time. e.g. class A{ int i; int j; char c; }; Here the offset of c = 8 bytes from the start of an object of A (assuming 4 byte int). Can it be done at compile time. Thanks in advance
7
7052
by: p.lavarre | last post by:
How do I vary the byte offset of a field of a ctypes.Structure? How do I "use the dynamic nature of Python, and (re-)define the data type after the required size is already known, on a case by case basis"? \\\ For example, suppose sometimes I receive the value '\x03hi' + \x04bye' for the struct:
0
9728
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, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
1
10402
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
10135
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
9205
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7670
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6890
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
5554
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4339
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
3018
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.