没有结构对象的C指针算术

C pointer arithmetic without object of structure

本文关键字:指针 结构 对象      更新时间:2023-10-16

我认为这在C中是不可能的,但要求验证这一点。在没有这种类型的实变量的情况下,是否可以在结构成员之间进行算术?例如:

typedef struct _s1
{
int a;
int b;
int c;
} T1;

我想看看"c"成员相对于结构开头的偏移量。如果我有变量,这很容易:

T1 str;
int dist = (int)&str.c - (int)&str;

但我的结构太大了,RAM中没有成员(只有EEPROM)。我想做一些地址计算,但不想定义RAM成员。我可以用结构指针而不是结构变量来完成这项工作(它只需要4个字节),但这种情况对我来说很有趣

使用offsetof可以在成员之间进行计算,而无需获取该类型的变量。您所需要的只是类型本身和成员的名称。

注意为什么简单的计算可能不起作用:数据对齐。你不知道编译器会对你的结构进行多少填充,如果你改变结构,这可能会导致非常微妙的错误,或者使看似正确的计算出错。

首先,将各个地址强制转换为ints。我认为这不是一个好主意。保证int的大小至少为2字节或更大,地址/指针通常为4或8字节。把这些投给int是不对的。如果要将它们转换为任何类型,我可能会将unsigned long用于32位系统,将unsigned long long用于64位系统。为了安全起见,我会用后者
也就是说,我根本不会强制转换地址,只使用offsetof宏。

请注意,将#include <stddef.h>添加到文件中,并使用offsetof宏,该宏将偏移值强制转换为size_t类型,而不是int。它只需使用0作为结构的内存地址,然后返回给定成员的地址,给出实际偏移量:

size_t offset = offsetoff(T1, c);
//struct, member

正如Zack在评论中指出的,答案的下一部分有些无关紧要,但为了完整起见,我将把它留在这里,因为offsetof是所有实现所必需的:

如果由于某种原因没有stddef.h(它应该这样做,因为offsetof已经成为标准的一部分一段时间了:C89及以上),请自己定义宏,如下所示:

#ifndef offsetof
#define offsetof(s, m) ((size_t)&(((s *) 0)->m))
#endif

这应该奏效,但要小心:这种实现可能会导致未定义的行为。这里解释了如何以及为什么
我从这里找到的stddef.h源中获得了上面的offsetof定义,所以您可以下载该文件并使用它,而不是在自己的文件中定义宏,但请记住,您使用的offsetof不是100%可靠的。

不管怎样,这已经足够了,更多关于谷歌的信息,但这里有几个链接:

  • GCC文档
  • SO的相关问题
  • 另一个SO问题

您可以使用stddef.h中定义的offsetof

我知道这超出了您的要求,但offsetof有一个有趣的用法,例如在linux内核代码中使用的container_of宏。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);

stddef.h有一个名为offsetof的宏,它给出了成员从结构开头的偏移量。

size_t t = offsetof( T1 , c ) ;

这样就不必实际声明任何结构变量。

查看数据结构对齐

没错:

size_t dist = offsetof(struct _s1, c);

在标题stddef.h中有一个宏;CCD_ 22。你可以在你的结构上使用它,如下所示:

int dist = (int)offsetof(T1, c);