【发布时间】:2013-05-23 13:44:21
【问题描述】:
这与this question密切相关。
我正在使用libusb 编写一些 USB 代码。查看库的源代码,我看到他们正在使用指针来解析数据并填充structs。
例子:
来自libusb.h:
struct libusb_endpoint_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
uint8_t bRefresh;
uint8_t bSynchAddress;
const unsigned char *extra;
int extra_length;
};
来自descriptor.c:
struct libusb_endpoint_descriptor *endpoint
unsigned char *buffer
int host_endian
usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian);
usbi_parse_descriptor 在哪里:
int usbi_parse_descriptor(
unsigned char *source,
const char *descriptor,
void *dest,
int host_endian)
{
unsigned char *sp = source;
unsigned char *dp = dest;
uint16_t w;
const char *cp;
for (cp = descriptor; *cp; cp++) {
switch (*cp) {
case 'b': /* 8-bit byte */
*dp++ = *sp++;
break;
case 'w': /* 16-bit word, convert from little endian to CPU */
dp += ((uintptr_t)dp & 1); /* Align to word boundary */
if (host_endian) {
memcpy(dp, sp, 2);
} else {
w = (sp[1] << 8) | sp[0];
*((uint16_t *)dp) = w;
}
sp += 2;
dp += 2;
break;
}
}
return (int) (sp - source);
}
我的问题是使用char指针来遍历缓冲区。
-
uint8_t被编译器对齐为例如uint32_t整数——因此*dp++以错误的地址结束,这难道不是一种风险吗?
错误地址是指dp指向的structlibusb_endpoint_descriptor中变量的地址:unsigned char *buffer = REPLY from request to USB device. struct libusb_endpoint_descriptor *endpoint; unsigned char *dp = (void*) endpoint; *dp = buffer[0] ==> struct libusb_endpoint_descriptor -> bLength *++dp = buffer[1] ==> struct libusb_endpoint_descriptor -> bDescriptorType ... v ^ | | +--- does this guaranteed align with this ----------------+ -
这会发生什么?:
dp += ((uintptr_t)dp & 1); /* Align to word boundary */
如果内存中的结构是这样的:
ADDRESS TYPE NAME
0x000a0 uint8_t var1
0x000a1 uint16_t var2
0x000a3 uint8_t var3
和dp 指向var1; 0x000a0,上面的语句会做什么?
【问题讨论】:
-
部分答案:dp += ((uintptr_t)dp & 1); /* 对齐字边界 */ 将 dp 视为指针的整数表示(使用机器上的适当大小来表示指针)。如果指针指向一个奇数地址,它会将 1 添加到 dp。这样做会使 dp 在 16 位边界上对齐。继续,如果 dp 指向 var1,则该语句保持 dp 不变。如果它指向 &var2,则语句将 dp 移动到 &var3
-
实际上是将dp移动到var2的第二个字节,而不是var3(var2未对齐)。