1

我正在学习如何为 linux 编写设备驱动程序,并且我有一个关于使用通用数据结构的问题。

我有一个任务,我有完整的功能......所以我不要求你做我的家庭作业......

此分配要求设备能够将元素从 fifo 缓冲区中入队和出队。我使缓冲区“通用”,以便可以使用任何元素大小(并在运行时指定)。源码在下面(注意这不是内核版本,但错误是一样的)...内核版本需要kmalloc,copy_to/from_user()等...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct RB_Buffer
{
    void* RBData;
    unsigned int getindex;  //index to remove element
    unsigned int putindex;  //index to put element at
    unsigned int capacity;  //max elements buffer holds
    unsigned int elemCount; //num elements inserted
    unsigned int elemSize;  //size of each element
};

void* RB_kcreate(int numElements, unsigned int elementSize);
int putring(struct RB_Buffer *rbptr, void* data);
int getring(struct RB_Buffer *rbptr, void* data);


//Creates a Ring buffer of specified number of elements and element size.
//Returns void* pointer pointing to the RB_Buffer struct. This pointer can
//then be used on putring and getring functions.
void* RB_kcreate(int numElements, unsigned int elementSize)
{
    struct RB_Buffer *newBuf = malloc(sizeof(struct RB_Buffer));
    if(newBuf == NULL) return 0;
    newBuf->RBData = (void*)malloc(elementSize*numElements);//, GFP_KERNEL);
    if(newBuf->RBData == NULL)
    {
        free(newBuf);
        return 0;
    }
    newBuf->capacity = numElements;
    newBuf->elemSize = elementSize;
        newBuf->getindex = 0;
        newBuf->putindex = 0;
        newBuf->elemCount = 0;

    return newBuf;
}

//puts an element in the buffer. Returns -1 if full, 0 on success
//send data through void* data argument
int putring(struct RB_Buffer *rbptr, void* data)
{
    int i = 0;
    if ( rbptr->elemCount >= rbptr->capacity )
        return -1;

    memcpy(&rbptr->RBData[rbptr->putindex * rbptr->elemSize], data, rbptr->elemSize);
    rbptr->putindex++;
    if (rbptr->putindex >= rbptr->capacity )
        rbptr->putindex = 0;
    rbptr->elemCount++;

    return 0;
}

//removes an element in the buffer. Returns -1 if empty, 0 on success
//data is returned through the data pointer
int getring(struct RB_Buffer *rbptr, void *data)
{
    if ( !rbptr->elemCount )
        return -1;


    rbptr->elemCount--;
    memcpy(data, &rbptr->RBData[rbptr->getindex * rbptr->elemSize], rbptr->elemSize);
    rbptr->getindex++;
    if ( rbptr->getindex >= rbptr->capacity )
        rbptr->getindex = 0;

    return 0;

}

当我将它编译成内核模块时,我收到警告:

kringbuf_generic.c:53: warning: dereferencing ‘void *’ pointer kringbuf_generic.c:72: warning: dereferencing ‘void *’ pointer

错误发生在putring中(在memcpy中)

if ( rbptr->elemCount >= rbptr->capacity )
            return -1;

        memcpy(&rbptr->RBData[rbptr->putindex * rbptr->elemSize], data, rbptr->elemSize);
        rbptr->putindex++;

在 getring 中,在 memcpy() 函数中

rbptr->elemCount--;
        memcpy(data, &rbptr->RBData[rbptr->getindex * rbptr->elemSize], rbptr->elemSize);
        rbptr->getindex++;

显然,由于这是一个内核模块,所以不知道谁会使用它,并且固定缓冲区元素大小将限制此缓冲区的使用。

有没有办法摆脱警告?还是在开发此类代码时我应该做一些不同的基本事情?

4

1 回答 1

4

我认为问题在于这段代码:

rbptr->RBData[rbptr->getindex * rbptr->elemSize]

正在尝试对 指向的数组进行索引,该数组RBData的类型为void *。您不能有意义地使此操作对void*指针起作用,因为在 C 中对数组进行索引需要您知道数组中元素的大小,并且根据定义 avoid*是指向未知类型元素的指针。

无论如何,大多数编译器都允许您通过将 a 隐式转换void*为 achar*并仅读取原始字节值来执行此操作。但是,这样做确实不是一个好主意,因为操作没有明确定义。

要解决此问题并使警告静音,请考虑在取消引用之前将RBData字段显式类型转换为 a :char*

((char *)rbptr->RBData)[rbptr->getindex * rbptr->elemSize]

或者,只需将其作为 a 存储char*在您的结构中,以避免重复执行此类型转换。

希望这可以帮助!

于 2011-02-18T22:52:31.950 回答