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.
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 typevoid *
, 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 ofvoid *
pointers with object pointers in assignments and relationals, while requiring explicit casts for other pointer mixtures.