Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Feb 2001 11:23:32 -0800 (PST)
From:      Matt Dillon <dillon@earth.backplane.com>
To:        "Jacques A. Vidrine" <n@nectar.com>
Cc:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: portability sanity check
Message-ID:  <200102211923.f1LJNWl24375@earth.backplane.com>
References:   <20010221094228.A93221@hamlet.nectar.com>

next in thread | previous in thread | raw e-mail | index | archive | help
:Is the following portable and safe?
:
:Given n different structure declarations, where each structure begins
:with the same member type, can any instance of any of the structures
:be cast to the (pointer) type of the first member?
:
:e.g.
:
:   struct foo {
:       const char *s;
:       ...
:   };
:
:   struct bar {
:       const char *s;
:       ...
:   };
:
:   int gefahr(struct foo *Foo, struct bar *Bar) {
:       return strcmp((const char *s)Foo, (const char *s)Bar);
:   }
:
:Likewise if the first member were a more complex data type, but
:nevertheless the same between the different structures.
:
:It seems safe to me, but I can't explain why :-)
:
:Cheers,

    Probably safe, but not a good idea.  Why not simply pass blah->s
    to the routine instead?  One trick I use, when a subroutine needs
    the first N headers of a structure, is create an embedded 'header'
    structure:

    struct base {
	a
	b
	c
    }

    struct fubar1 {
	struct base base;
	x
	y
	z
    }

    struct fubar2 {
	struct base base;
	h
	i
	j
    }

    struct fubar3 {
	...
    }

    callsomesubroutine(&fubar2->base);


    The calling direction is not the problem.  It's the return value that
    is usually a problem.  For example, a doubly-linked list function might
    look like this:

    void *
    getNextNode(Node *previousNode)
    {
	return(previousNode->next);
    }

    struct fubar {
	Node node;
	...
    }

    struct fubar *fu;

    for (fu = getHeadOfList(&List); fu; fu = getNextNode(&fu->node)) {
    }

    There are ways around this, at least if the contents of a list is
    uniform.  FreeBSD's kernel's /usr/src/sys/sys/queue.h implements
    macros for all of its list functions that actually create special node
    structures with previous and next pointers of exactly the proper type
    for however they are used.  I generally use the 'void *' return value
    trick myself, to make the code more readable at the cost of a slight
    loss in type checking.  But I only use it for return values... arguments
    are still required to be the proper exact type.

					-Matt


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200102211923.f1LJNWl24375>