1、windows平台下有offsetof宏可以求得结构体成员变量便宜,源码如下:
windows下有个CONTAINING_RECORD
/* Define offsetof macro */
#ifdef __cplusplus
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&reinterpret_cast<const volatile char&>((((s *)0)->m)) )
#else
#define offsetof(s,m) (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
#endif
#else
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)//零地址得出的偏移,相当NULL指针,->符号并没有去执行代码,编译器只是取成员域的地址,避免对象创建,效率大大提高,往往在面试题中出现
#endif
#endif /* __cplusplus */
2、同样的道理,知道成员变量地址,结构体类型,成员名称,就可以求得:结构体开始地址 = 成员变量地址-offset
windows下有个CONTAINING_RECORD
#define CONTAINING_RECORD(address,type,field) ((type*)((PCHAR)(address)-(ULONG_PTR)(&((type*)0)->field)))
3、Linux的链表和hash表就用到了这种技术
在linux内核中,链表没有保存数据域,链表节点作为数据节点的域,遍历全局链表或者hash表时,利用上面1、2两点得数据节点的地址。跟一般的链表操作相反。
example 1.1 数据节点结构体
749struct inode {
750 umode_t i_mode;
751 unsigned short i_opflags;
752 uid_t i_uid;
753 gid_t i_gid;
754 unsigned int i_flags;
755
756#ifdef CONFIG_FS_POSIX_ACL
757 struct posix_acl *i_acl;
758 struct posix_acl *i_default_acl;
759#endif
760
761 const struct inode_operations *i_op;
762 struct super_block *i_sb;
763 struct address_space *i_mapping;
764
765#ifdef CONFIG_SECURITY
766 void *i_security;
767#endif
768
769 /* Stat data, not accessed from path walking */
770 unsigned long i_ino;
771 /*
772 * Filesystems may only read i_nlink directly. They shall use the
773 * following functions for modification:
774 *
775 * (set|clear|inc|drop)_nlink
776 * inode_(inc|dec)_link_count
777 */
778 union {
779 const unsigned int i_nlink;
780 unsigned int __i_nlink;
781 };
782 dev_t i_rdev;
783 struct timespec i_atime;
784 struct timespec i_mtime;
785 struct timespec i_ctime;
786 spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
787 unsigned short i_bytes;
788 blkcnt_t i_blocks;
789 loff_t i_size;
790
791#ifdef __NEED_I_SIZE_ORDERED
792 seqcount_t i_size_seqcount;
793#endif
794
795 /* Misc */
796 unsigned long i_state;
797 struct mutex i_mutex;
798
799 unsigned long dirtied_when; /* jiffies of first dirtying */
800
801 struct hlist_node i_hash; //hash链表
802 struct list_head i_wb_list; /* backing dev IO list */
803 struct list_head i_lru; /* inode LRU list */
804 struct list_head i_sb_list;
805 union {
806 struct list_head i_dentry;
807 struct rcu_head i_rcu;
808 };
809 atomic_t i_count;
810 unsigned int i_blkbits;
811 u64 i_version;
812 atomic_t i_dio_count;
813 atomic_t i_writecount;
814 const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
815 struct file_lock *i_flock;
816 struct address_space i_data;
817#ifdef CONFIG_QUOTA
818 struct dquot *i_dquot[MAXQUOTAS];
819#endif
820 struct list_head i_devices;
821 union {
822 struct pipe_inode_info *i_pipe;
823 struct block_device *i_bdev;
824 struct cdev *i_cdev;
825 };
826
827 __u32 i_generation;
828
829#ifdef CONFIG_FSNOTIFY
830 __u32 i_fsnotify_mask; /* all events this inode cares about */
831 struct hlist_head i_fsnotify_marks;
832#endif
833
834#ifdef CONFIG_IMA
835 atomic_t i_readcount; /* struct files open RO */
836#endif
837 void *i_private; /* fs or device private pointer */
838};
example 1.2 链表定义
struct list_head {
223 struct list_head *next, *prev;
224 };
225
226 struct hlist_head {
227 struct hlist_node *first;
228 };
229
230 struct hlist_node {
231 struct hlist_node *next, **pprev;
232 };