这与 this question 密切相关.
我正在使用libusb
编写一些USB代码。查看该库的源代码,我发现它们正在使用指针来解析数据并填充结构
。
示例:
来自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++
最终地址错误?
我所说的错误地址是指libusb_endpoint_descriptor
结构体中dp
指向的变量的地址: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
,上面的语句会做什么?
最佳答案
关于你的第二个问题,地址只是一个整数,只是编译器使用它来表示内存位置。表达式 ((uintptr_t)dp & 1)
的作用是首先将其转换为适当的整数(类型 uintptr_t
是一个足以容纳指针的整数),并检查最低有效位是否已设置。如果未设置该位,则表达式的结果为零,这意味着该地址是偶数且 16 位对齐。如果该位被设置,则意味着地址不均匀并且不是 16 位对齐的。
这个表达式的有趣之处在于,它会产生 0
或 1
结果,具体取决于该位是否未设置。如果未设置该位,则将 0
添加到已经 16 位对齐的地址中,从而不会发生任何变化。另一方面,如果地址不是 16 位对齐,则表达式会导致 1
添加到地址,自动将其对齐到 16 位边界。
关于c - 使用指针在结构体中的元素之间移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16715593/