Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 无结构对象的C指针算法_C++_C_Pointers_Math - Fatal编程技术网

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成

我认为这在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个字节)来完成这项工作,但这个例子对我来说很有趣。

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<<代码>: