2011-02-18 4 views
1

J'apprends comment écrire des pilotes de périphériques pour Linux, et j'ai une question concernant l'utilisation des structures de données génériques.pilote de périphérique du noyau « déréférencement pointeur « void * »

J'ai une mission, que j'ai pleinement fonctionnel ... donc je ne vous demande pas de faire mes devoirs ...

Cette affectation nécessite un périphérique pour pouvoir mettre en file d'attente et retirer des éléments d'un tampon FIFO. La taille de l'élément peut être utilisée (et spécifiée à l'exécution) La source est incluse ci-dessous (notez que ce n'est pas la version du noyau, mais l'erreur est la même) ... la version du noyau requiert kmalloc, copy_to/from_user() etc ...

#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; 

} 

Quand je compile ce dans un module du noyau, je reçois les avertissements:

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

L'erreur se produit ici à putring (en memcpy)

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

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

et ici getring , dans la fonction memcpy()

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

Évidemment, puisqu'il s'agit d'un module noyau, on ne sait pas vraiment qui va l'utiliser, et la fixation de la taille de l'élément tampon limiterait l'utilisation de ce tampon.

Y a-t-il un moyen de se débarrasser des avertissements? Ou y a-t-il quelque chose de fondamental que je devrais faire différemment en développant un tel code?

+0

Désolé, je ne vais pas compter les lignes pour savoir quelle est la ligne 72. Mais ne pouvez-vous pas éliminer l'avertissement avec un classeur? –

+0

Serait bien si vous nous avez dit où l'erreur se produit. Je suppose que c'est la ligne copy_to_user? Quel est le deuxième argument pour copy_to_user? – EboMike

+0

désolé lol, corrigé. changé le code en une version que n'importe qui peut utiliser (noyau non). – user623879

Répondre

4

Je pense que le problème est que ce code:

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

tente d'index dans le tableau pointé par RBData, qui est de type void *. Vous ne pouvez pas vraiment faire fonctionner cette opération sur un pointeur void*, car indexer dans un tableau en C nécessite de connaître la taille des éléments dans le tableau, et par définition un void* est un pointeur vers des éléments d'un type inconnu.

La plupart des compilateurs vous permettent de faire cela de toute façon en transposant implicitement le void* en char* et en lisant simplement les valeurs d'octets bruts. Cependant, ce n'est vraiment pas une bonne idée de le faire, car l'opération n'est pas bien définie.

Pour résoudre ce problème et faire taire l'avertissement, tenez compte typecasting explicitement le champ RBData à un char* avant déréférencement il:

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

Ou bien, stocker tout comme un char* dans votre struct pour éviter d'avoir à faire à plusieurs reprises ce typecast.

Espérons que cela aide!

+0

Merci! Cela aide vraiment. Plus d'avertissements! – user623879

Questions connexes