【问题标题】:Why does this code use a *char as a buffer pointer?为什么这段代码使用 *char 作为缓冲区指针?
【发布时间】:2026-02-11 06:55:02
【问题描述】:

在寻找可重用的循环缓冲区代码时,我遇到了一个让我困惑的 char 用法

typedef struct CircularBuffer
{
    void *buffer;     // data buffer
    void *buffer_end; // end of data buffer
    size_t capacity;  // maximum number of items in the buffer
    size_t count;     // number of items in the buffer
    size_t sz;        // size of each item in the buffer
    void *head;       // pointer to head
    void *tail;       // pointer to tail
} CircularBuffer;

void cb_push_back(CircularBuffer *cb, const void *item)
{
    if(cb->count == cb->capacity)
        // handle error
        memcpy(cb->head, item, cb->sz);

    ////////////// here's the part I don't understand //////////
    cb->head = (char*)cb->head + cb->sz;
    //////////////////////////////////////////////////////////

    if(cb->head == cb->buffer_end)
        cb->head = cb->buffer;
    cb->count++;
}

为什么要将此 void 指针转换为 char?这是某种 C 习语吗(我的 C 经验非常有限)?也许是一种增加指针的便捷方法?

在一些不同的缓冲区代码中也再次出现使用 char 作为位置指针:

/**< Circular Buffer Types */
typedef unsigned char INT8U;
typedef INT8U KeyType;
typedef struct
{
    INT8U writePointer; /**< write pointer */
    INT8U readPointer;  /**< read pointer */
    INT8U size;         /**< size of circular buffer */
    KeyType keys[0];    /**< Element of ciruclar buffer */
} CircularBuffer;

再一次,这看起来像是 C 程序员知道的某种方便的技巧,如果指针是字符,那么指针很容易操作。但我真的只是在猜测。

【问题讨论】:

  • 仅供参考:该类型称为char*,而不是*char
  • 这是我第一次看到struct的名字是typedef的名字,这很奇怪……

标签: c pointers char


【解决方案1】:

转换为char * 是为了让指针运算正确执行,如果你想以一个字节为单位移动指针;这总是有效的,因为char 根据定义具有 1 个字节的大小。相反,使用 void * 指针的指针运算不是由 C 标准定义的,因为 void 没有指定单个项目的大小。

另一个常见的 C 习惯用法(与此相关)是当您想以“原始字节”访问某些内存时使用 unsigned char *unsigned 类型允许您访问每个字节的无符号值而无需强制转换);它也经常用于typedefed(类似于typedef unsigned char byte;),以更清楚地表明您不想将内存解释为字符,而是作为原始字节。

【讨论】:

    【解决方案2】:

    char 的大小为一个字节,因此当您想将内存的某个区域简单地作为字节数组进行操作时,可以使用它(或 signed charunsigned char)。

    【讨论】:

    • 那么没有标准的字节大小(heh)数字类型吗?
    【解决方案3】:

    Void 指针只是指向一个值,没有类型信息。所以不可能对 void 指针执行加法。指针运算需要将其转换为其他类型。这里将 void * 转换为 char *,然后添加 cb->sz,假设 char 的大小为 1,向前移动 size 个字节。

    【讨论】:

    • 不需要假设。 sizeof(char) == 1 是有保证的。
    【解决方案4】:

    强制转换启用指针算术;没有它,因为cb-&gt;headvoid* 类型,表达式cb-&gt;head + cb-&gt;sz 将没有意义。

    一旦指针被转换为char*,指针加法(char*)cb-&gt;head + cb-&gt;sz意味着“对象地址cb-&gt;size经过cb-&gt;head指向的字节。

    【讨论】: