c - 使用指针在结构体中的元素之间移动

标签 c memory struct

这与 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指针来遍历缓冲区。

  1. 不可能冒着 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 ----------------+
    
  2. 这会发生什么?:

    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指向var10x000a0,上面的语句会做什么?

最佳答案

关于你的第二个问题,地址只是一个整数,只是编译器使用它来表示内存位置。表达式 ((uintptr_t)dp & 1) 的作用是首先将其转换为适当的整数(类型 uintptr_t 是一个足以容纳指针的整数),并检查最低有效位是否已设置。如果未设置该位,则表达式的结果为零,这意味着该地址是偶数且 16 位对齐。如果该位被设置,则意味着地址不均匀并且不是 16 位对齐的。

这个表达式的有趣之处在于,它会产生 01 结果,具体取决于该位是否未设置。如果未设置该位,则将 0 添加到已经 16 位对齐的地址中,从而不会发生任何变化。另一方面,如果地址不是 16 位对齐,则表达式会导致 1 添加到地址,自动将其对齐到 16 位边界。

关于c - 使用指针在结构体中的元素之间移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16715593/

相关文章:

c - 为什么我的顶点法线会随着相机旋转而旋转?

c - 从现有文件描述符分配一个结构体 - c

ios - 定义结构时的错误信息

c - 转换为 void* 和基本结构指针之间是否存在性能差异?

mtrace 可以用 valgrind 成功运行吗?

c - 使用 SIGUSR1 的两个进程之间的 Posix 可靠信号

curl - 在 Golang 中使用 curl 在网站上搜索字符串最有效和可扩展的等价物是什么?

python - 我可以通过Python手动访问特定的内存地址吗

c - 为 fgets 中的结构体数组分配内存

c - 理解 C 结构