offsetof()

Add comments to offsetof() wiki to understand its implementation.

The "traditional" implementation of the macro relied on the compiler obtaining the offset of a member by specifying a hypothetical structure that begins at address zero:

#define offsetof(st, m) \
    ((size_t)&(((st *)0)->m))

This can be understood as taking a null pointer of type structure st, and then obtaining the address of member m within said structure. While this implementation works correctly in many compilers, it has generated some debate if this is undefined behavior according to the C standard,[2] since it appears to involve a dereference of a null pointer (although, according to the standard, section 6.6 Constant Expressions, Paragraph 9, the value of the object is not accessed by the operation). It also tends to produce confusing compiler diagnostics if one of the arguments is misspelled.[citation needed]

Comments 1: Actually there is no dereference at all. A dereference occurs when the * or -> is used on an address value to find referenced value. The only use of * above is in a type declaration for the purpose of casting. The -> operator is used above but it's not used to access the value. Instead it's used to grab the address of the value. See stackoverflow for more details.

Comments 2: will &(((st *)0)->m) leads to undefined behavior (UB), since (st *)0 does not point to any object and use ((st *)0)->m? As stackoverflow states, from a lawyer point of view, the expression should lead to UB, since you could not find a path in which there would be no UB. Since compiler use this form, it may allow program use same form or issue a warning when use compiler to compile the program......

An alternative is:

#define offsetof(st, m) \
    ((size_t)((char *)&((st *)0)->m - (char *)0))

It may be specified this way because the standard does not specify that the internal representation of the null pointer is at address zero. Therefore the difference between the member address and the base address needs to be made. Again, since these are constant expressions it can be calculated at compile time and not necessarily at run-time.

Comments: The 0 in offsetof() implementation stands for null pointer NULL as following. Since the standard does not specify whether NULL is 0 or not, it may be 0 or may be other value. If it's 0, then following implementation is fine. But if NULL is not 0, say it's 0xffff ffff, then following implementation will produce 0xffff ffff+m's offset, so need minus 0xffff ffff.

#define offsetof(st, m) \
    ((size_t)&(((st *)NULL)->m))

Some modern compilers (such as GCC) define the macro using a special form (as a language extension) instead, e.g.[3]

#define offsetof(st, m) \
    __builtin_offsetof(st, m)

This builtin is especially useful with C++ classes or structs that declare a custom unary operator &.[4]

Comments: not familiar it.

It's said that offsetof() is a compile time macro, but I don't know why? It may come clear later.

`memcpy()` 和 `offsetof()` 都是在 C 编程语言中使用的函数,分别用于数据复制和获取结构体成员偏移地址的功能。 ### memcpy() `memcpy()` 函数是一个库函数,通常包含于 `<string.h>` 头文件中。它用于将一个指定大小的数据块从源位置复制到目标位置。其语法形式大致如下: ```c void *memcpy(void *dest, const void *src, size_t n); ``` 其中, - `dest` 是指向目标存储区的指针; - `src` 是指向源存储区的指针; - `n` 是需要复制的字节数。 例如,在两个数组之间的复制操作可以像下面这样实现: ```c char str1[] = "Hello"; char str2; memcpy(str2, str1, sizeof(str1)); // 此时 str2 的内容会被设置为 'H', 'e', 'l', 'l', 'o' ``` ### offsetof() `offsetof()` 函数也是一个宏,同样位于 `<stddef.h>` 或 `<stdalign.h>` 头文件中,用于计算结构体成员相对于结构体起始处的偏移量。它的基本语法如下: ```c #define offsetof(struct_type, member_name) ((size_t)(intptr_t)&((struct_type *)0)->member_name) ``` 这里, - `struct_type` 是结构体的名称(实际上是指向该结构体类型的指针类型); - `member_name` 是想要获取偏移量的成员变量名。 例如,如果有一个结构体 `Person` 包含姓名、年龄等信息,你可以使用 `offsetof()` 来获取某个字段的位置: ```c struct Person { char name[20]; int age; }; // 获取名字字段相对于 Person 结构体的偏移量 size_t name_offset = offsetof(struct Person, name); ``` ### 相关问题: 1. `memcpy()` 和 `memmove()` 之间有何区别? 2. `offsetof()` 对于结构体和联合体有何影响? 3. 如何有效利用 `memcpy()` 和 `offsetof()` 提高程序性能?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值