近日在进行大小端转换时碰到一个关于二级指针的问题,为避免遗忘,在此整理。
原代码如下
#include <stdio.h>
#define Little ('l')
#define Big ('b')
#define uint8_t char
#define uint16_t short
union order_help
{
uint8_t c[4];
unsigned long l;
};
typedef union order_help order_help_t;
const order_help_t _order;
uint8_t order() { return (uint8_t)(_order.l); }
uint16_t ByteOrderSwitch16(uint16_t value)
{
return (((value & 0x00ff) << 8) | ((value & 0xff00) >> 8));
}
int switchU16(int _order, uint8_t **_buf, uint16_t _size, uint16_t *_v)
{
if (_size < 2)
{
return 0;
}
uint8_t *tmp = (uint8_t *)_v;
//memcpy(tmp, (UInt8 *)(*_buf), 2);
printf("buf0:%#x\n", **_buf);
tmp[0] = *_buf;
*_buf++;
printf("buf1:%#x\n", **_buf);
tmp[1] = *_buf;
*_buf++;
printf("tmp0:%#x tmp1:%#x _v:%p %x\n", tmp[0], tmp[1], _v, *_v);
if (_order != order())
{
*_v = ByteOrderSwitch16(*_v);
}
//*((UInt8*)_buf) += 2;
return 1;
}
int main ()
{
uint8_t buf[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
uint16_t ret = 0;
char *p_buf = buf;
switchU16(Big, &p_buf, 2, &ret);
printf("ret = %#x\n", ret);
uint8_t *temp = (uint8_t *)&ret;
temp[0] = 0x07;
temp[1] = 0x08;
printf("temp:%p temp[0]:%p %d temp[1]:%p %d ret:%p %#x\n",
temp, &temp[0], temp[0], &temp[1], temp[1], &ret, ret);
return 0;
}
以上代码实现两个功能:
1:将数组前两个字节进行大小端转换
2:指针后移两个字节
注:由于memcy有时会出现问题所以改用直接赋值的方法。
但是运行后出现问题两个问题:
1:段错误
2:输出的值错误
经排查发现问题所在:
问题1:段错误是因为
*_buf++;
所以上段代码旨在将传入的指针向后移,但是因为“右++”优先级>“*”优先级,所以造成段错误,应改为
(*_buf)++;
问题2:赋值错误问题是因为
uint8_t *tmp = (uint8_t *)_v;
printf("buf0:%#x\n", **_buf);
tmp[0] = *_buf;
由于传入的是二级指针“**_buf”,申请了一级指针“*tmp”,而"tmp[0]"表示该指针下的值,所以上述代码实际上是把二级指针下的一级指针地址赋给了“tmp[0]”,导致赋值错误。
经验证:上述推论正确:
buf0:0x1
buf1:0x2
tmp0:0xffffffd0 tmp1:0xffffffd1 _v:0x7fffccd8b6be ffffd1d0
ret = 0xffffd0d1
正确输出结果应为:
buf0:0x1
buf1:0x2
tmp0:0x1 tmp1:0x2 _v:0x7fffc0831dde 201
ret = 0x102
temp:0x7fffc0831dde temp[0]:0x7fffc0831dde 7 temp[1]:0x7fffc0831ddf 8 ret:0x7fffc0831dde 0x807