C语言指针加1问题以及字节对齐问题

今天早上自己写了一段代码,然后测试的时候发现结果总是和预期的不一样,而且偏差的有点离谱,冥思苦想了将近五个小时,最后在我要开始怀疑人生的时候,发现原来是自己犯了一个极其低级但又容易被忽略的问题。好吧,我承认我有点丢程序员的人了。

废话不多说,直接开始用例子来说明吧:

我的代码里有两个结构体,假设为结构体Head和结构体Data,其结构如下:

struct Data{
     int a;
     char b;
     short c;
     long d;    
};

struct Head{
     int fieldcount;
     Data fielddata[1];
};

其中,结构体Head包含结构体Data的指针,且fieldcount表示后续有多少Data。我是将这个数据存储在缓冲区中(假设缓冲区为char buf[1024])。当我通过如下代码取数据的时候,发现取出来的数据结构体Data完全不是自己要的:

1         Head* h = (Head*) (buf+offset);
2         size_t datalen = sizeof (Head) + (h->fieldcount-1) * sizeof (Data);
3         offset += datalen;
4 
5         for(size_t i=0;i<h->fieldcount;++i)
6         {
7             Data* data=(Data*)(h+sizeof(Head)+(i-1)*sizeof(Data));
8             printf("a: %d b: %c 
", data->a,data->b);
9         }

不知道大家看出来问题没有,我竟然研究这一段这么简单的代码研究了五个小时,简直丢人啊。直接说问题吧。问题出在这句代码:

1 Data* data=(Data*)(h+sizeof(Head)+(i-1)*sizeof(Data));

我的本意是想依次取出来Head后面的data的,即通过Data指针操作内存。可是我却忘记了(指针+偏移量)的含义了。这里的偏移量看起来很正确,是以字节为单位的数,其实对于指针来说,是加了偏移量*sizeof(Head)的字节数,这里的偏移量,意思是加了多少个Head,这也是指针的奇妙之处,也是平时容易忽略的地方。所以每次我读Data的时候,总是读的很靠后面的内存,到时候读的数据存在问题。修改后的代码如下:

1 Data* data=(Data*)((char*)h+sizeof(Head)+(i-1)*sizeof(Data));

当然,我的环境是在linux上,以utf-8为编码格式,所以char是一个字节,当然这里具体环境可以修改代码。

温馨提示:

在调试代码的时候,还发现一个容易出错的地方,就是注意字节对齐问题。当你把数据存到缓冲区时,如果数据是字节对齐,例如以1字节对齐的时候,如果取得时候没有声明对齐,那会存在意想不到的效果,哈哈聪明的你可以尝试,反正我是尝试过了。

原文地址:https://www.cnblogs.com/fnlingnzb-learner/p/7667579.html