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

i48*_*486 36 c c++ math pointers

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

typedef struct _s1
{
  int a;
  int b;
  int c;
} T1;
Run Code Online (Sandbox Code Playgroud)

我希望看到"c"成员与结构开始相比的偏移量.如果我有变量很容易:

T1 str;

int dist = (int)&str.c - (int)&str;
Run Code Online (Sandbox Code Playgroud)

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

pmr*_*pmr 57

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

请注意为什么简单计算可能无法解决:数据对齐.您不知道编译器将在您的结构中抛出的填充量,如果更改结构,这可能会导致非常微妙的错误或使看似正确的计算错误.


Eli*_*gem 25

首先,您将个人地址转换为ints.我认为这不是一个好主意.的int保证是至少2个的大小字节或更多,一个地址/指针通常是4或8个字节.将这些投射到int恰好并不合适.如果我将它们转换为任何东西,我可能会使用unsigned long32位系统和unsigned long long64位系统.我会用后者来保证安全.
也就是说,我根本不会转发地址,只使用offsetof宏.

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

size_t offset = offsetoff(T1, c);
                    //struct, member
Run Code Online (Sandbox Code Playgroud)

正如Zack在评论中指出的那样,答案的下一部分有点无关紧要,但对于它所包含的链接,为了完整起见,我将把它留在这里 - 正如offsetof所有实现所要求的那样:

如果由于某种原因你没有stddef.h,你自己定义宏(它应该是,因为offsetof现在已经成为标准的一部分:C89及以上),如下所示:

#ifndef offsetof
#define offsetof(s, m) ((size_t)&(((s *) 0)->m))
#endif
Run Code Online (Sandbox Code Playgroud)

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

无论如何,现在已经足够了,Google上有更多信息,但这里有几个链接:

  • 定义`offsetof`有点危险.你展示的实现是一个未定义行为的边界情况(我可以为此挖掘一个参考),但它可以为实现者做到这一点,因为他们知道(或必须确保)编译器的行为. (6认同)
  • 没有理由没有提供`stddef.h`的实现,其中包含`offsetof`,现在 - 从C89开始,它已经被所有实现所需,独立或其他. (2认同)

fed*_*024 16

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

我知道这超出了你的要求,但有一个有趣的用途,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) );})
Run Code Online (Sandbox Code Playgroud)

你可以使用例如:

// 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);
Run Code Online (Sandbox Code Playgroud)

  • @EliasVanOotegem我认为(char*)是必要的,因为后来__mptr用于指针算术.它需要精确地通过offsetof(...)字节递减.你永远不应该在viud指针上使用算术http://stackoverflow.com/questions/3523145/pointer-arithmetic-for-void-pointer-in-c (2认同)

thi*_*his 12

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

size_t t = offsetof( T1 , c ) ;
Run Code Online (Sandbox Code Playgroud)

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


Dav*_*eri 10

看看数据结构对齐

那是对的:

size_t dist = offsetof(struct _s1, c);
Run Code Online (Sandbox Code Playgroud)


Ant*_*ony 8

在标题中stddef.h有一个宏; offsetof.您可以在结构上使用它,如下所示:

int dist = (int)offsetof(T1, c);
Run Code Online (Sandbox Code Playgroud)