字节偏移引起的读写错误


  今天又被一个同事叫查问题,他从网络上接收一个结构体数据,然后根据偏移获取值,但是总是获取不对,由于涉及结构体嵌套,一直怀疑是发送方问题,查了好久最后发现是解析的时候计算偏移出了问题,这样的类似问题在我印象中不止一次了,上次也时一个同事遇到了类似问题。所以今天我有必要记录一下,加深映像,希望下次遇到能够快速发现问题;

在这不方便贴出原问题代码,下面给出另外一个实例,问题都是一样的。

// TestStructOffiset.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <string.h>
#include <stdlib.h>

typedef struct ProductInfo
{
    int nProductId;
    int nDateLen;
    char data[0];
}*pProductInfo,sProductInfo;

typedef struct DetailClass
{
    int nClassId;
    int nNumber;
    char Detail[255];
}*pDetailClass,sDetailClass;

void GetDetailInfo(pProductInfo pParameter)
{
    printf("nProductId %d\n",pParameter->nProductId);

    //错误计算偏移
    printf("base %p and base+offset %p \n",pParameter,pParameter+sizeof(sProductInfo));
    pDetailClass pTemp = (pDetailClass)(pParameter+sizeof(sProductInfo));   // 方式一
    printf("classid and number %d,%d\n",pTemp->nClassId,pTemp->nNumber);

    //正确计算偏移
    printf("base %p and base+offset and %p \n",pParameter,(char *) pParameter+sizeof(sProductInfo));
    pDetailClass pTemp1 = (pDetailClass)((char *)pParameter+sizeof(sProductInfo)); // 方式二
    printf("classid and number %d,%d\n",pTemp1->nClassId,pTemp1->nNumber);
}

/*
void GetDetailInfo2(char* pParameter)
{
    pProductInfo pProTemp = (pProductInfo)pParameter;
    printf("nProductId %d\n",pProTemp->nProductId);

    //计算偏移
    printf("%p and %p \n",pParameter,pParameter+sizeof(sProductInfo));
    pDetailClass pTemp = (pDetailClass)(pParameter+sizeof(sProductInfo));
    printf("pTemp %d,%d\n",pTemp->nClassId,pTemp->nNumber);
}*/

int _tmain(int argc, _TCHAR* argv[])
{
     int nLen = sizeof(sProductInfo)+sizeof(sDetailClass);

     char *buf = (char *)malloc(sizeof(sProductInfo)+sizeof(sDetailClass));
     if (NULL == buf)
     {
         printf("malloc failed !");
         getchar();
         retrun -1;
     }
     memset(buf,0,nLen);

     pProductInfo pProTmp = (pProductInfo)buf;
     pProTmp->nProductId = 1;
     pProTmp->nDateLen = sizeof(sDetailClass);

     sDetailClass sDetailTmp;
     sDetailTmp.nClassId = 2;
     sDetailTmp.nNumber = 0;

     memcpy_s(pProTmp->data,sizeof(sDetailClass),&sDetailTmp,sizeof(sDetailClass));

     GetDetailInfo(pProTmp);

     //GetDetailInfo2((char *)pProTmp);

     getchar();

	return 0;
}

执行结果:

nProductId 1
base 00423208 and base+offset 00423248  ----- 偏移了64个字节(十六进制)
classid and number -858993460,-858993460  ----- 错误;读取字节与预期不符
base 00423208 and base+offset and 00423210 ----- 偏移了8个字节
classid and number 2,0                     ----- 正确读取值

分析结果:

由于pParameter所指向的结构体大小为8个字节,然后移动sizeof(sProductInfo) = 8 个单位,实际就是移动了8*sizeof(sProductInfo) = 64个字节;而DetailClass 的偏移地址实际为 8个字节;所以方式一读取错误;方式二才是正解;

结论:

1、在利用指针给非单字节(如本文中的结构体或int 等)类型计算偏移时,一定要注意是否需要转为单字节类型的指针(如char *)再计算偏移值。

2、这种情况传参数的时候不要传结构体指针,而是将结构体指针转为char * 传入,再实际使用时再进行转换。如本文中注释的方法GetDetailInfo2调用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值