Linux的stddef.h定义offsetof()为:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
Run Code Online (Sandbox Code Playgroud)
而维基百科上的文章offsetof()(http://en.wikipedia.org/wiki/Offsetof)将其定义为:
#define offsetof(st, m) \
((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
Run Code Online (Sandbox Code Playgroud)
为什么减去(char *)0维基百科版本?有什么情况会真正有所作为吗?
我有一个结构定义为:
struct smth
{
char a;
int b[];
};
Run Code Online (Sandbox Code Playgroud)
当我打电话sizeof,并offsetof在这个结构:
cout << sizeof(struct smth) << endl;
cout << offsetof(struct smth, b) << endl;
Run Code Online (Sandbox Code Playgroud)
输出是:
4
4
Run Code Online (Sandbox Code Playgroud)
为什么当stuct的大小是4而char使用1个字节时,int数组的偏移量是4?为什么会有某种填充?另外,为什么int数组根本不占用任何空间?
这个问题是关于使用带有结构偏移的指针算法导出的指针.
考虑以下程序:
#include <cstddef>
#include <iostream>
#include <new>
struct A {
float a;
double b;
int c;
};
static constexpr auto off_c = offsetof(A, c);
int main() {
A * a = new A{0.0f, 0.0, 5};
char * a_storage = reinterpret_cast<char *>(a);
int * c = reinterpret_cast<int *>(a_storage + off_c));
std::cout << *c << std::endl;
delete a;
}
Run Code Online (Sandbox Code Playgroud)
该程序似乎可以工作,并使用默认设置和C++ 11标准在我测试的编译器上给出预期结果.
(A密切相关的程序,在这里我们使用void *的,而不是char *和static_cast代替reinterpret_cast,没有被普遍接受.gcc 5.4发出关于与空指针的指针算术警告,并clang 6.0说,与指针算法void *是错误的.) …
代码适用于int,但是当我想使用float时它会失败,除非我将结构转换为字符指针.这是它的样子:
struct test
{
float a;
float b;
};
void stuff(int offset, test* location);
int main()
{
test *t;
t = (test*)malloc(sizeof(test));
char choice = '\0';
//Find the byte offset of 'a' within the structure
int offset;
printf("Edit a or b?");
scanf("%c", &choice);
switch (toupper(choice))
{
case 'A':
offset = offsetof(test, a);
stuff(offset, t);
break;
case 'B':
offset = offsetof(test, b);
stuff(offset, t);
break;
}
printf("%f %f\n", t->a, t->b);
return 0;
}
void stuff(int offset, test* location)
{
float imput; …Run Code Online (Sandbox Code Playgroud) 我一直在寻找很长很长的时间(最后的链接)来解释 offsetof MACRO 的实现:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
Run Code Online (Sandbox Code Playgroud)
特别是,取消引用 NULL 以获得结构中成员的偏移量。许多文章通过说 NULL 指针实际上从未真正取消引用来掩盖原因,但这对我来说没有意义。
以下是我尝试理解的一些链接:
我正在寻找并试图理解的是对编译器如何解释 MACRO 定义的逐步分解理解,这最终将解释 NULL 指针实际上没有被取消引用。
编辑:尽管其他问题回答了我的疑问,但正如原始帖子中所指出的那样,它们对我来说没有意义。@dasblinkenlight 的回答揭示了我在回答其他问题时遇到的确切问题,即我们实际上没有取消引用指针是怎么回事。
我打开stddef.h并看到了这个:
#if defined _MSC_VER && !defined _CRT_USE_BUILTIN_OFFSETOF
#ifdef __cplusplus
#define offsetof(s,m) ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
#else
#define offsetof(s,m) ((size_t)&(((s*)0)->m))
#endif
#else
#define offsetof(s,m) __builtin_offsetof(s,m)
#endif
Run Code Online (Sandbox Code Playgroud)
在__cplusplus(在C++编译器的情况下)的分支中有非常奇怪的实现,我认为它是多余的.其他分支(C编译器的情况)具有更简单的字段偏移计算.我测试了它,它的工作原理.对于在第一种情况下使用这种奇怪的强制转换和类型限定符的内容?
我想得到一个子元素的总offSetTop和总offSetLeft,它们有很多级别的父元素,可能正在加起来.
除了以手动方式逐个添加之外,这是否是任何简写方式?
struct Data {
int a;
std::string b;
float c;
};
std::string* allocateDataAndGetString() {
Data* dataPtr(someAllocator.allocate<Data>());
return &dataPtr.b;
}
Data* getBaseDataPtrFromString(std::string* mStringMember) {
// ???
}
int main() {
std::string* stringPtr(allocateDataAndGetString());
Data* dataPtr(getBaseDataPtrFromString
}
Run Code Online (Sandbox Code Playgroud)
我Data在堆上分配了一个实例,并指向了它的std::string b;成员.如何Data以标准方式获取字符串所属实例的基址,并考虑偏移和填充?
我试过减sizeof(int)并std::offsetof(Data, std::string)从std::string*指针,但我无法得到它的工作.
我期待在宏观offsetof的<cstddef>,看到一个可能的实现是通过
#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))
Run Code Online (Sandbox Code Playgroud)
我尝试过它确实按预期工作
#include <iostream>
#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))
struct S
{
char x;
short y;
int z;
};
int main()
{
std::cout << my_offsetof(S, x) << '\n';
std::cout << my_offsetof(S, y) << '\n';
std::cout << my_offsetof(S, z) << '\n';
S s;
std::cout << (void*) &((&s)->x) << '\n'; // no more relative offsets
std::cout << (void*) &((&s)->y) << '\n'; // no more relative offsets
std::cout << (void*) &((&s)->z) << '\n'; // …Run Code Online (Sandbox Code Playgroud) offsetof定义如下stddef.h:
#define offsetof(type, member) ((size_t)&((type *)0)->member)
Run Code Online (Sandbox Code Playgroud)
是否由于取消引用NULL指针而调用未定义的行为?如果没有,为什么?