C++ 无结构对象的C指针算法
我认为这在C语言中是不可能的,但请验证这一点。在没有这种类型的实变量的情况下,可以在结构构件之间进行算术运算吗?例如:C++ 无结构对象的C指针算法,c++,c,pointers,math,C++,C,Pointers,Math,我认为这在C语言中是不可能的,但请验证这一点。在没有这种类型的实变量的情况下,可以在结构构件之间进行算术运算吗?例如: typedef struct _s1 { int a; int b; int c; } T1; 我想查看“c”成员相对于结构开始的偏移量。如果我有变量,这很容易: T1 str; int dist = (int)&str.c - (int)&str; 但我的结构太大了,RAM中没有成员(只有EEPROM)。我想做一些地址计算,但不想定义RAM成
typedef struct _s1
{
int a;
int b;
int c;
} T1;
我想查看“c”成员相对于结构开始的偏移量。如果我有变量,这很容易:
T1 str;
int dist = (int)&str.c - (int)&str;
但我的结构太大了,RAM中没有成员(只有EEPROM)。我想做一些地址计算,但不想定义RAM成员。我可以用结构指针而不是结构变量(只需要4个字节)来完成这项工作,但这个例子对我来说很有趣。
stddef.h
有一个名为的宏,它给出了成员从结构开始的偏移量
size_t t = offsetof( T1 , c ) ;
这样您就不必实际声明任何结构变量。在标题
stddef.h
中有一个宏。您可以在结构上使用它,如下所示:
int dist = (int)offsetof(T1, c);
看看
没错:
size_t dist = offsetof(struct _s1, c);
使用可以在成员之间进行计算,而不必掌握该类型的变量。您所需要的只是类型本身和成员的名称
简单计算可能无法实现的一个注意事项:数据对齐。您不知道编译器将对您的结构进行多少填充,如果您更改结构,这可能会导致非常细微的错误,或使看似正确的计算出错。首先,您要将各个地址强制转换为
int
s。我认为这不是个好主意。int
的大小保证至少为2个字节或更多,地址/指针通常为4或8个字节。将这些值转换为int
并不合适。如果要将它们转换为任何类型,我可能会对32位系统使用无符号长
,对64位系统使用无符号长
。为了安全起见,我会使用后者。size_t t = offsetof( T1 , c ) ;
也就是说,我根本不会强制转换地址,只使用offsetof
宏
添加#将包含到文件中,并使用offset of
宏,该宏将偏移值强制转换为size\t
类型,而不是int
。它只需使用0作为结构的内存地址,然后返回给定成员的地址,给出实际偏移量:
size_t offset = offsetoff(T1, c);
//struct, member
正如扎克在评论中指出的那样,答案的下一部分有些无关紧要,但出于完整性的考虑,我将把它留在这里,因为所有实现都需要offsetof
:
如果出于某种原因(它应该这样做,因为offsetof
已经成为标准的一部分一段时间了:C89及以上),您可以自己定义宏,如下所示:
#ifndef offsetof
#define offsetof(s, m) ((size_t)&(((s *) 0)->m))
#endif
这应该可以做到,但要小心:这个实现可能会导致未定义的行为
我从上面的偏移量定义中获取了偏移量,因此您可以下载该文件并使用它,而不是在您自己的文件中定义宏,但请记住,您使用的偏移量并不是100%可靠的
不管怎样,这就足够了,更多关于谷歌的信息,但这里有几个链接:
您可以使用中定义的
我知道这超出了您的要求,但有一个有趣的用法是offsetof
,例如在linux内核代码中使用了宏的容器container_of
可以返回父结构的地址,给定指向其成员之一的指针:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
例如,您可以使用:
// pointer_to_c points to a member of the struct, c in this case
// and you want to get the address of the container
T1 *container;
container = container_of(pointer_to_c, T1, c);
定义伪指针,看看吧?这里可能已经回答了这个问题,其他地方也讨论了无数次。我想答案应该是谷歌搜索。你用谷歌搜索过吗?@EliasVanOotegem考虑到提到EEPROM,这很有可能是在嵌入式系统上运行的。就我们所知,它可能是一个8位或16位系统。旁白:您的示例代码可能应该是(char*)&str.c-(char*)&str
。我手头没有参考资料,但我认为你实际上不能保证将指针转换为int
,然后进行算术运算就能得到正确的结果。(此外,如果您要将指针投射到整数,则应使用intptr\u t
或uintptr\u t
)@如果您认为这很重要,那么请找到答案所在并投票以重复方式关闭。定义offsetof
有点危险。您展示的实现是一个未定义行为的边界情况(我可以为此挖掘一个参考),但是为实现者这样做是可以的,因为他们知道(或必须确保)编译器的行为。@pmr:在我的答案中添加了一些关于此的链接,谢谢您向我指出。我不知道
的怪癖(我的C“知识”的主要来源是K&R,它根本没有提到宏)。无论如何,+1对于您指出OPF的数据对齐的答案,现在没有理由不提供stddef.h
,其中包含偏移量
,这是自C89以来所有独立或其他实现所必需的。我喜欢宏的容器,但(char*)
cast对我来说有点像是遗产,如果你不介意我这么说的话。我认为现在,我们应该使用一个空白pointer@EliasVanOotegem我认为(char*)是必要的,因为后面的mptr用于指针算术。它需要精确递减(…)字节的偏移量。你不应该在viud指针上使用算术好点。。。我刚才看到了<代码>(char *),MPTR ,没有停止考虑<代码> Valu*-sieZiT<<代码>: