我想使用指针算法从数据包结构中获取一些字段。但是下面的代码有什么问题?
在第一个条件我认为如果我从数据包的开头去4字节(2短字段)我得到tLow。但它没有给出预期的值。另外第二种情况我想通过从数据包的开头走12字节来获取数据字段。我的想法有问题吗?
struct packet{
short len;
short field;
int tLow;
int tHigh;
void *data;
}
int main()
{
struct packet pack;
struct packet *pck;
pack.len=3;
pack.field=34;
pack.tLow=712;
pack.tHigh = 12903;
pack.data = "message";
pck = &pack;
int *timeLow = (int * )pck + 4; // i want to get tLow
printf("Time Low :%d\n",*time);
char *msg = (char *)pck + 12 ;// want data
printf("Message :%s\n",msg);
return 0;
}
答案 0 :(得分:3)
使用标准方法
肯定会更好int *timeLow = &(pck->tLow);
允许编译器在结构的任何成员之间插入填充字节。这些填充字节的规则充其量只是实现定义...所以你必须参考你的实现手册来确定在你的特定情况下如何(或如果)和插入多少字节。另请注意,填充字节数可能会从编译更改为使用不同选项编译或从编译器更改为编译器(计算机到计算机,......)
您可以尝试使用C
宏offsetof
,但它并不漂亮:
size_t offset = offsetof(struct packet, tLow);
/* make sure offset is a multiple of sizeof (int*) */
int *timeLow = (int*)pck + offset / sizeof (int*);
或者,使用强制转换为(char*)
并从其他答案中复制代码稍微不那么难看: - )
size_t offset = offsetof(struct packet, tLow);
int *timeLow = (int*)((char*)pck + offset);
哦!你的来源
中缺少一个分号答案 1 :(得分:2)
您正在寻找 offsetof 。
您的代码可能如下所示:
int *timeLow = (int*) ((char*)pck + offsetof(struct packet, tLow);
正如pmg指出的那样,
int *timeLow = &(pck->tLow);
是获取指向结构成员的指针的规范方法。
这个答案也带来了pointer arithmetics - 我今天学到了这一点,这要归功于pmg。
答案 2 :(得分:2)
基本上你依赖于未定义的行为。结构对齐等等但无论如何......
(int *)pck + 4.将指针4 * sizeof(int)前进。这是错误的,如果我们假设结构被打包并且sizeof(short)== 2,我们希望将它提前1,因此......
int *timeLow = (int * )pck + 1; // i want to get tLow
printf("Time Low :%d\n",*timeLow);
打印出正确的结果。
至于消息,你需要做一些肮脏的事情。由于我在x86_64上,编译器选择在8字节边界上填充void *,因此偏移量为16而不是预期的12。
我们基本上是获取指向void *的指针。所以代码看起来像这样:
char **msg = (char**)((char *)pck + 16) ;// want data
printf("Message :%s\n",*msg);
从不编写这样的代码,这只是说明了一点。
答案 3 :(得分:1)
当你写
int *timeLow = (int * )pck + 4
您将'pck'视为一个int指针,这取决于您的系统可能是4或8个字节。 这将无法正确地偏移到结构中,因为您告诉它具有4 int
的偏移量相反,你需要这样做
int *timeLow = (int*)((short * )pck + 2);
答案 4 :(得分:0)
短裤不一定是2个字节长。所有指定的是它们小于或等于整数的大小。你可能应该使用sizeof()
答案 5 :(得分:0)
这是错误的:pack.data = "message";
您正在使用未分配的内存。
此外:int *timeLow = (int * )pck + 4;
不能保证工作(结构对齐在编译器和系统之间有所不同)。