You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言memcpy等函数如何处理不支持算术运算的void*数组

C标准库通用内存操作函数的实现逻辑

void*指针的处理核心逻辑

C标准确实明确禁止void*类型指针直接进行算术运算:因为void没有确定的大小,编译器无法计算偏移的步长。
标准库中所有接收void*参数的通用函数(比如memcpy、memmove、memset、qsort等),本质都是绕开了按原始类型操作的需求,直接把内存当成字节序列处理。

memcpy的简化实现原理

这类函数的核心操作只有两步:

  • 首先把传入的void*强制转换为unsigned char*类型,unsigned char的大小固定为1字节,对其做算术运算完全符合C标准要求
  • 按照传入的字节长度参数,以单字节为单位完成内存的拷贝、移动、填充等操作

以下是无优化的最简memcpy实现样例:

void* my_memcpy(void* restrict dest, const void* restrict src, size_t byte_len) {
    unsigned char* d = (unsigned char*)dest;
    const unsigned char* s = (const unsigned char*)src;

    for (size_t i = 0; i < byte_len; i++) {
        d[i] = s[i];
    }
    return dest;
}

生产环境的memcpy会额外增加对齐判断、按机器字长批量拷贝、SIMD指令优化等逻辑,但核心的指针转换逻辑和上面的样例完全一致。

对你的通用list实现的参考方案

你目前遇到的void* data无法直接运算的问题,可以参考标准库的思路解决,常用有两种落地方式:

  • 底层接口对标标准库设计:所有操作函数都要求传入单元素的字节长度,内部统一转unsigned char*按字节偏移访问元素,示例接口如下:
    // 向list的pos位置插入元素
    int list_insert(list_t* list, size_t pos, const void* elem, size_t elem_size);
    // 读取list的pos位置的元素指针,由调用方自行做类型转换
    void* list_at(const list_t* list, size_t pos, size_t elem_size);
    
  • 上层用宏封装简化调用:保留你之前用宏实现模板的思路,把类型转换、元素大小计算的逻辑封装到宏里,用户调用时不需要手动处理类型和长度参数,示例宏如下:
    // 自动计算元素大小、传入取址后的元素
    #define LIST_INSERT(list, pos, elem, type) list_insert(list, pos, &(elem), sizeof(type))
    // 自动把返回的void*转换为对应类型的左值
    #define LIST_AT(list, pos, type) (*(type*)list_at(list, pos, sizeof(type)))
    

内容的提问来源于stack exchange,提问作者dumb_ptr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 10:24:06