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

ここでエラーが発生します(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*は不明なタイプの要素へのポインターであるため、この操作をポインターで意味のある形で機能させることはできません。

void*ほとんどのコンパイラでは、を暗黙的にキャストし、char*生のバイト値を読み取るだけで、とにかくこれを行うことができます。ただし、操作が明確に定義されていないため、これを行うことは実際にはお勧めできません。

これを修正して警告を消音するには、逆参照RBDataする前にフィールドを明示的に型キャストすることを検討してください。char*

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

char*または、この型キャストを繰り返し実行する必要がないように、構造体にとして保存することもできます。

お役に立てれば!

于 2011-02-18T22:52:31.950 に答える