1
votes

void * comme paramètre de fonction

J'ai des problèmes avec void *. Comment dois-je faire pour utiliser cette fonction clean_buffer pour les tableaux int et float.

void clean_buffer( void *ptr, int n)
{
    for( int i = 0; i < n; i++)
        ptr[i]=0;
}
int main(void)
{
   float  *pf;
   int    *pi;

   pf = (float *) malloc(10*sizeof(float));
   pi = (int *)malloc(10*sizeof(int));


   clean_buffer( (float *)pf, 10);
   clean_buffer( (int *)pi, 10);

    return 0;
}

c

6 commentaires

Êtes-vous sûr de ne pas vouloir utiliser memset au lieu de clean_buffer? La norme IEEE 754 garantit que la remise à zéro d'un tampon flottant définira les valeurs sur 0,0f.


Vous pouvez plutôt transmettre la taille du tampon en octets . Mais à ce stade, vous écrivez un memset moins efficace. Alors utilisez simplement ça .


Vous n'avez jamais besoin de convertir quoi que ce soit dans son propre type, comme dans (float *) pf .


De plus, votre objectif est-il ici de mettre à zéro les tampons immédiatement après leur attribution? Si tel est le cas, vous pouvez utiliser calloc qui initialise la mémoire à zéro pour vous.


@SirDarius D'après le titre, il semble qu'il s'agisse de l'utilisation des pointeurs void * en général, l'extrait de code n'étant qu'un MCVE à titre d'illustration.


@Gerhardh alors que le titre est générique, la question elle-même est assez spécifique, et borde un problème X-Y (poser une question sur une solution, et non sur le problème à résoudre, c'est-à-dire. Mes questions demandent des éclaircissements à OP pour s'assurer que c'est bien le cas.


6 Réponses :


0
votes

Vous lancez ptr dans le type approprié afin qu'il puisse être déréférencé pour effacer ce sur quoi il pointe; quelque chose que vous connaissez pointe vers un type dont vous souhaitez effacer les éléments i .


0 commentaires

2
votes

void est une valeur non que vous ne pouvez pas utiliser * ((void *) x) = v; et utiliser un cast à utiliser un pointeur vers un autre type est dangereux car la taille peut ne pas être la même

Mais, dans votre cas, vous définissez sur 0, vous pouvez donc utiliser memset ou remplacer le malloc mon calloc et il est inutile d'avoir clean_buffer :

int main(void)
{
   float  *pf;
   int    *pi;

   pf = calloc(10, sizeof(float));
   pi = calloc(10, sizeof(int));

   return 0;
}


4 commentaires

clean_buffer () n'est pas toujours inutile. Un bloc qui se termine par {void * p; ... memset (p, 0, 10); } est soumis à l'optimisation en abandonnant l'appel memset () . Le clean_buffer () peut être là pour nettoyer la mémoire du point de vue de la sécurité. Il est probable que volatile soit également appliqué pour éviter son optimisation.


@chux Dans le cas actuel, calloc est certainement le meilleur moyen ;-)


Le message d'OP n'est pas certain que l'utilisation de clean_buffer () est uniquement pour la première affectation. clean_buffer (p, n) peut être appelé pendant toute la durée de vie de p .


calloc () est bon et préférable si l'objectif est uniquement l'initialisation à 0, considérez pf = calloc (10, sizeof * pf); comme plus facile à coder correctement, examinez et maintenir.



2
votes

Le type void n'a pas de taille. Par conséquent, vous ne pouvez pas utiliser void * pour effacer un tableau. Vous ne pouvez pas déréférencer ce type pour la même raison.

Vous devez effectuer un cast vers un pointeur avec un type spécifique:

int main(void)
{
   float  *pf;
   int    *pi;

   pf = malloc(10*sizeof(float));
   pi = malloc(10*sizeof(int));

   clean_buffer( pf, 10*sizeof(float));
   clean_buffer( pi, 10*sizeof(int));

   return 0;
}

Vous devez veiller à ce que la taille transmise à votre La fonction ne peut pas être le nombre ou les tableaux car le compilateur ne peut pas faire d'arithmétique de pointeur avec des pointeurs void * . Et pour les tailles, vous devez utiliser size_t

Au lieu de cela, vous devez passer la taille du tableau en octets:

void clean_buffer(void *ptr, size_t n)
{
    unsigned char *my_ptr = ptr;
    for (int i = 0; i < n; i++)
        my_ptr[i]=0;
}

Ou vous devez transmettre toute autre information pouvant être utilisée pour déterminer le type et / ou la taille des données.

Aussi: Le cast de la valeur de retour de malloc n'est pas nécessaire en C. Le cast des paramètres de clean_buffer vers un type que la variable a déjà, est inutile. Le type de pointeur est de toute façon converti en void * car c'est ce que la fonction attend.

Remarque: D'autres réponses et commentaires mentionnent que vous pouvez simplement passer le pointeur vers memset ou utiliser calloc etc. Cela peut être vrai pour ce cas très spécifique, mais si vous voulez faire autre chose que simplement remettre à zéro la mémoire, les mêmes aspects concernant les pointeurs void * s'appliquent comme je l'ai montré ici. Et dans ces cas, memset ou calloc ne sont d'aucune utilité.


0 commentaires

0
votes

void clean_buffer (void * ptr, int n)

Cette fonction requiert un void * comme paramètre.

clean_buffer ((float *) pf, 10);

Ici, vous lancez vers un pointeur flottant. Donc, c'est un type différent comme demandé

De plus, void n'a pas de taille, donc vous ne pouvez pas vraiment utiliser [] sur ptr


0 commentaires

0
votes

malloc lui-même renvoie un pointeur vide car il ne sait pas vraiment pour quel type vous allouez de la mémoire. Donc, vous devez utiliser la même taille que celle que vous passez à malloc pour effacer également le tampon.

Vous pouvez utiliser memset et transmettre la taille du tampon entier pour l'effacer sans avoir à vous soucier de son type.

void clean_buffer( void *ptr, size_t n)
{
    memset(ptr, 0, n)
}
int main(void)
{
   float  *pf;
   int    *pi;

   pf = (float *) malloc(10*sizeof(float));
   pi = (int *)malloc(10*sizeof(int));


   clean_buffer(pf, 10*sizeof(float));
   clean_buffer(pi, 10*sizeof(int));

    return 0;
}

De plus, comme d'autres l'ont suggéré, vous pouvez utiliser calloc si cela vous convient.


0 commentaires

1
votes

J'ai des problèmes avec void *. Comment dois-je faire pour utiliser cette fonction clean_buffer pour les tableaux int et float (?)

D'autres ont mentionné des choses utiles comme la nécessité de sizeof pour trouver la taille, le cast non nécessaire et des alternatives pour utiliser calloc () pour une allocation de mémoire initialisée à zéro.

/ p>


Pour ajouter:

sizeof * object_pointer

Utilisez sizeof * object_pointer pour trouver le Taille. Il est moins sujet aux erreurs, plus facile à examiner et à maintenir que le codage dans le type.

void clean_buffer(void *ptr, size_t n) {
  volatile unsigned char *vuc = ptr;
  for(size_t i = 0; i < n; i++)
    vuc[i]=0;
  }
}

volatile

Nettoyage de la mémoire après son utilisation finale a tendance à être optimisée et donc une bonne raison de ne pas utiliser memset () lorsque la sécurité de la mémoire est préoccupante. Utilisez plutôt volatile pour éviter que clean_buffer () ne soit lui-même optimisé.

// clean_buffer( (float *)pf, 10);
// clean_buffer( (int *)pi, 10);

// cast not needed
clean_buffer(pf, sizeof *pf * 10);  // No need to mention type!
clean_buffer(pi, sizeof *pi * 10);

0 commentaires