clinuxunixkernelnetbsd

casting operations on vnode (in NetBSD)


In NetBSD system file usr/src/sys/sys/vnode.h defines structure of a vnode. However, I see that sometime while performing an operation (lets say ufs_getattr) a vnode* is passed as a void* to the called operation.

Each such operation has its arguments structure. For Ex, ufs_getattr() the structure is as follows:

struct vop_getattr_args /* {
                struct vnode    *a_vp;
                struct vattr    *a_vap;
                kauth_cred_t    a_cred;
};

Generally, first line of these operations perform an assignment of vnode pointer, which was actually a void*, into a pointer of this argument type pointer. For Example, we do something like :

int
ufs_getattr(void *v)
{
        struct vop_getattr_args /* {
                struct vnode    *a_vp;
                struct vattr    *a_vap;
                kauth_cred_t    a_cred;
        } */ *ap = v;            //why this is okay to do ?
        struct vnode    *vp;
        struct inode    *ip;
        struct vattr    *vap;

        vp = ap->a_vp;           //wont this break ?

Extracted from usr/src/sys/ufs/ufs/ufs_vnops.c

Due to very little C programming knowledge I am unable to justify this mismatched assignment as the types do not really match.


Solution

  • In C, assigning a void* to a T* is legal (not so in C++). Therefore the code's perfectly valid.

    Quoting "The C Programming Language 2nd Edition" by K&R:

    Any pointer to an object may be converted to type void * without loss of information. If the result is converted back to the original pointer type, the original pointer is recovered. Unlike the pointer-to-pointer conversions discussed in Par.A.6.6, which generally require an explicit cast, pointers may be assigned to and from pointers of type void *, and may be compared with them.


    As an interesting sidenote, something about the history of void* (from the same book):

    This interpretation of void * pointers is new; previously, char * pointers played the role of generic pointer. The ANSI standard specifically blesses the meeting of void * pointers with object pointers in assignments and relationals, while requiring explicit casts for other pointer mixtures.