Go Back   Velocity Reviews > Newsgroups > C Programming
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply

C Programming - Is this legal

 
Thread Tools Search this Thread
Old 11-06-2009, 03:28 PM   #1
Default Is this legal


I've been wrestling with my conscience over this one for several years
now. This is a cut down example of some code I've written to iterate
over any linked list as long as it satisfies a particular constraint.
But is it actually legal? - I can't make my mind up.

Here's roughly what it looks like. I could post the full code (it's
actually a mergesort rather than an iterator) if this has silly errors
in or doesn't explain it properly. But here goes:

I have a header file (list_header.h)
that just contains:

typedef void list_function(void *l);
void list_iterator(void *lst);

and a list code file like this:

#include "list_header.h"

struct generic_list {
struct generic_list *next;
};

void list_iterator(void *lst, list_function *lf) {
struct generic_list *p = lst;
while(*p) {
lf(p);
p = p->next;
}
}

Then, whenever you want to iterate over a list you do:
#include "list_header.h"

struct thislist {
struct thislist *next;
... lots of other fields ...
} *reallist;

void list_callback(void *l) {
struct thislist *lp = l;
... do things with all the other fields in lp ...
}

and then, deep in the bowels of the code, after reallist has been made
to point to a list of items
list_iterator(reallist,list_callback);

Now clearly if you ever use this with structures where the first item is
not a pointer to a list item you are heading for every type of error and
undefined behaviour.

But if not, is this legal? The dodgy bit is casting a pointer to one
type of list, via void, to another type of list and then dereferencing a
field within it and expecting it to point to another list of the second
type when it originally pointed to one of the first.

On the other hand, all the stuff I can read about the equivalence of
pointer suggests it just might be (it's clearly right on the border).
It works, has worked on various compilers and OSs, but I know that
proves absolutely nothing!

Thoughts?
--
Online waterways route planner: http://canalplan.org.uk
development version: http://canalplan.eu


Nick
  Reply With Quote
Old 11-06-2009, 04:08 PM   #2
nicolas.sitbon
 
Posts: n/a
Default Re: Is this legal
On 6 nov, 16:28, Nick <3-nos...@temporary-address.org.uk> wrote:
> I've been wrestling with my conscience over this one for several years
> now. *This is a cut down example of some code I've written to iterate
> over any linked list as long as it satisfies a particular constraint.
> But is it actually legal? - I can't make my mind up.
>
> Here's roughly what it looks like. *I could post the full code (it's
> actually a mergesort rather than an iterator) if this has silly errors
> in or doesn't explain it properly. *But here goes:
>
> I have a header file (list_header.h)
> that just contains:
>
> typedef void list_function(void *l);
> void list_iterator(void *lst);
>
> and a list code file like this:
>
> #include "list_header.h"
>
> struct generic_list {
> * struct generic_list *next;
>
> };
>
> void list_iterator(void *lst, list_function *lf) {
> * struct generic_list *p = lst;
> * while(*p) {
> * * lf(p);
> * * p = p->next;
> * }
>
> }
>
> Then, whenever you want to iterate over a list you do:
> #include "list_header.h"
>
> struct thislist {
> * struct thislist *next;
> * ... lots of other fields ...
>
> } *reallist;
>
> void list_callback(void *l) {
> * * *struct thislist *lp = l;
> * * *... do things with all the other fields in lp ...
>
> }
>
> and then, deep in the bowels of the code, after reallist has been made
> to point to a list of items
> list_iterator(reallist,list_callback);
>
> Now clearly if you ever use this with structures where the first item is
> not a pointer to a list item you are heading for every type of error and
> undefined behaviour.
>
> But if not, is this legal? *The dodgy bit is casting a pointer to one
> type of list, via void, to another type of list and then dereferencing a
> field within it and expecting it to point to another list of the second
> type when it originally pointed to one of the first.
>
> On the other hand, all the stuff I can read about the equivalence of
> pointer suggests it just might be (it's clearly right on the border).
> It works, has worked on various compilers and OSs, but I know that
> proves absolutely nothing!
>
> Thoughts?
> --
> Online waterways route planner:http://canalplan.org.uk
> * * * * * *development version:http://canalplan.eu


you probably want to write:
void list_iterator(void *lst, list_function *lf) {
struct generic_list *p = lst;
while(p) { /* <========== */
lf(p);
p = p->next;
}

}


nicolas.sitbon
  Reply With Quote
Old 11-06-2009, 04:17 PM   #3
Seebs
 
Posts: n/a
Default Re: Is this legal
On 2009-11-06, Nick <3-> wrote:
> I've been wrestling with my conscience over this one for several years
> now. This is a cut down example of some code I've written to iterate
> over any linked list as long as it satisfies a particular constraint.
> But is it actually legal? - I can't make my mind up.


I'm not sure about "legal", I prefer "conforming" -- legal is itself a
term of art referring to the legal system.

> typedef void list_function(void *l);
> void list_iterator(void *lst);


> and a list code file like this:
>
> #include "list_header.h"
>
> struct generic_list {
> struct generic_list *next;
> };
>
> void list_iterator(void *lst, list_function *lf) {


Presumably the prototype matches, though.

> But if not, is this legal? The dodgy bit is casting a pointer to one
> type of list, via void, to another type of list and then dereferencing a
> field within it and expecting it to point to another list of the second
> type when it originally pointed to one of the first.


So far as I can tell, this should be covered by "all struct pointers smell
the same". All struct pointers have the same traits, and that means that
a "struct foo *next;" as a first member is a common initial sequence, so
the conversion from one to the other should preserve that common initial
sequence.

That said, someone (I've forgotten who already) recently pointed out a
more elegant solution, using a "struct list" which is embedded in a
structure anywhere you want. You iterate over the list, and when you
have the list member you want, you then grab the pointer to the containing
structure, because you know the offset of the "struct list" within that
structure. (Note that the member of the structure is a struct list, NOT
a struct list *.)

-s
--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!


Seebs
  Reply With Quote
Old 11-06-2009, 04:47 PM   #4
Nick
 
Posts: n/a
Default Re: Is this legal
Seebs <usenet-> writes:

> So far as I can tell, this should be covered by "all struct pointers smell
> the same". All struct pointers have the same traits, and that means that
> a "struct foo *next;" as a first member is a common initial sequence, so
> the conversion from one to the other should preserve that common initial
> sequence.


That's what I thought, but it's nice to have my opinion confirmed by a
respected authority (well, respected by a long-term lurker like me,
anyway).
>
> That said, someone (I've forgotten who already) recently pointed out a
> more elegant solution, using a "struct list" which is embedded in a
> structure anywhere you want. You iterate over the list, and when you
> have the list member you want, you then grab the pointer to the containing
> structure, because you know the offset of the "struct list" within that
> structure. (Note that the member of the structure is a struct list, NOT
> a struct list *.)


That sounds interesting. There's the obvious generic list container (a
struct with a next and a void pointer in it) but we're clearly not
talking about that.

At first I thought you wouldn't know where to find it, but of course the
callback function knows what structure it's expecting, so can use
offsetof to do it.

Checking up on offsetof (I don't believe I've ever used it) I see that
the Wikipedia article on it is an example of just this technique. It
involves a particularly horrible cast to avoid the compiler subtracting
an offsetof number of sizeof(structures) rather than bytes though.

That's really rather neat indeed. I don't think I'll be rewriting my
code, but I'll keep it in mind in case I ever have to do it again - it's
clearly safer than having to put the "next" field in the right place.
--
Online waterways route planner: http://canalplan.org.uk
development version: http://canalplan.eu


Nick
  Reply With Quote
Old 11-06-2009, 07:11 PM   #5
Phil Carmody
 
Posts: n/a
Default Re: Is this legal
Nick <3-> writes:
> Seebs <usenet-> writes:
>> So far as I can tell, this should be covered by "all struct pointers smell
>> the same". All struct pointers have the same traits, and that means that
>> a "struct foo *next;" as a first member is a common initial sequence, so
>> the conversion from one to the other should preserve that common initial
>> sequence.

>
> That's what I thought, but it's nice to have my opinion confirmed by a
> respected authority (well, respected by a long-term lurker like me,
> anyway).


Alas the respected gentleman is mistaken. Confusing sprouts with onions?

Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1


Phil Carmody
  Reply With Quote
Old 11-06-2009, 11:53 PM   #6
Barry Schwarz
 
Posts: n/a
Default Re: Is this legal
On Fri, 06 Nov 2009 15:28:04 +0000, Nick
<3-> wrote:

>I've been wrestling with my conscience over this one for several years
>now. This is a cut down example of some code I've written to iterate
>over any linked list as long as it satisfies a particular constraint.
>But is it actually legal? - I can't make my mind up.
>
>Here's roughly what it looks like. I could post the full code (it's
>actually a mergesort rather than an iterator) if this has silly errors
>in or doesn't explain it properly. But here goes:
>
>I have a header file (list_header.h)
>that just contains:
>
>typedef void list_function(void *l);
>void list_iterator(void *lst);
>
>and a list code file like this:
>
>#include "list_header.h"
>
>struct generic_list {
> struct generic_list *next;
>};
>
>void list_iterator(void *lst, list_function *lf) {
> struct generic_list *p = lst;
> while(*p) {
> lf(p);
> p = p->next;
> }
>}
>
>Then, whenever you want to iterate over a list you do:
>#include "list_header.h"
>
>struct thislist {
> struct thislist *next;
> ... lots of other fields ...
>} *reallist;
>
>void list_callback(void *l) {
> struct thislist *lp = l;
> ... do things with all the other fields in lp ...
>}
>
>and then, deep in the bowels of the code, after reallist has been made
>to point to a list of items


If you mean that reallist has been assigned a value that is the
address of a struct thislist, then all the implicit conversions
between pointers to void and pointers to struct appear valid. Though
not impossible, it would be an extremely perverse implementation that
decided a struct generic_list required a more restrictive alignment
than a struct thislist. If that were to be the case, the
initialization in list_iterator could invoke undefined behavior,
depending on the value of reallist.

Similarly, if you ever set reallist to point to a struct thatlist
which had less restrictive alignment than struct thislist, the
initialization in list_callback could invoke undefined behavior.

>list_iterator(reallist,list_callback);
>
>Now clearly if you ever use this with structures where the first item is
>not a pointer to a list item you are heading for every type of error and
>undefined behaviour.
>
>But if not, is this legal? The dodgy bit is casting a pointer to one
>type of list, via void, to another type of list and then dereferencing a
>field within it and expecting it to point to another list of the second
>type when it originally pointed to one of the first.


But that does not appear to be the case you describe. While the
various pointers (both the parameter pointers to void and the local
pointers to struct) have different types, at all times the value is
the address of the "list of items" you mention.

>
>On the other hand, all the stuff I can read about the equivalence of
>pointer suggests it just might be (it's clearly right on the border).
>It works, has worked on various compilers and OSs, but I know that
>proves absolutely nothing!


--
Remove del for email


Barry Schwarz
  Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Can you 'threaten legal action' in a email? Desk Rabbit Computer Support 6 03-12-2009 10:14 AM
Legal Advisor in India arunkhurana2@gmail.com Computer Support 3 08-16-2006 05:47 AM
"MAKE QUICK LEGAL EASY MONEY!!!!!!!!!!!!!!!!!!!!!!" bozo A+ Certification 0 02-28-2005 04:58 PM
Free Money!!! This Really Works!!! Free Money Guy! Computer Information 14 04-27-2004 06:52 AM
Its easy and its legal jon hayes Computer Support 5 10-31-2003 09:23 PM




SEO by vBSEO 3.3.2 ©2009, Crawlability, Inc.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46