Partage
  • Partager sur Facebook
  • Partager sur Twitter

Recoder la fonction memset

'void*' is not a pointer-to-object type

Sujet résolu
14 juin 2011 à 13:44:08

Bonjour !

Je suis en train de recoder la fonction memset du standard C et j'ai quelques problèmes.
D'abord, voici mon code la ou j'en suis rendu :

void *memset (void * s, int c, size_t n)
{
    unsigned int i(0);
    for(i = 1; i <= n; i++)
    {
        *(s) + i = c;
    }
    return s;
}


Maintenant les questions :)

1) Avant de déclarer ma variable i en unsigned, j'avais un avertissement de MinGW :
comparison between signed and unsigned integer expressions
J'en ai déduis que ma variable i devais être déclaré en étant non signé. Mais pourquoi ?

2) Quand j'essaye de compiler mon code, voici l'erreur que j'obtient : 'void*' is not a pointer-to-object type
Je suis persuadé que l'erreur viens du fait que ma variable s est un pointeur sur void.
Après quelques recherches j'ai appris qu'un pointeur sur void n'était pas déréférensable.
Or ma fonction reçoit obligatoirement un paramètre s ayant pour type un pointeur sur void. Comment faire alors ?

Merci d'avance.

EDIT: la 2ème erreur viens de l'affectation à la ligne 6.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
14 juin 2011 à 13:49:45

Pour la première erreur : Tu as tenté de convertir ton paramètre n de type size_t en unsigned int dans le corps de ta fonction ?

Pour le deuxième erreur, je dirais que

*(s) + i = c;


Devrait plutot s'écrire

*(s + i) = c;


(vérifie tes indices pour ta boucle après ça , on ne sait jamais)

J'ai raison ou je dis une bêtise ?
  • Partager sur Facebook
  • Partager sur Twitter
14 juin 2011 à 13:56:02

Citation : mewtow

J'ai raison ou je dis une bêtise ?


C'est une autre erreur, mais ce n'est pas l'erreur indiquée : void * ne peut pas être déréférencé.
Pour parrer ce problème, je pense qu'il faudrait caster en (char *)(unsigned char *), et caster c en (unsigned char) (c'est ce que j'ai cru comprendre en lisant le man).

Edit : concernant le type de i, je pense qu'il faudrait mieux le déclarer en tant que size_t.
Et il y a un problème de parcours.

Edit2 : Ouais, c'est vrai que (unsigned char *) c'est mieux.
  • Partager sur Facebook
  • Partager sur Twitter
14 juin 2011 à 14:02:41

Citation : Olytron


J'en ai déduis que ma variable i devais être déclaré en étant non signé. Mais pourquoi ?


Les comparaisons signed unsigned sont délicates, ce qui justifie l'émission d'un warning.

Par exemple

int main(void)
{
    int a = -2;
    unsigned int b = 3;

    if(a < b)
        puts("a < b");
    else
        puts("Oo ?!...");

    return 0;
}

Oo ?!...

Process returned 0 (0x0)   execution time : 0.031 s
Press any key to continue.


Citation : Olytron


Quand j'essaye de compiler mon code, voici l'erreur que j'obtient : 'void*' is not a pointer-to-object type



Tu ne peux pas déférencer un pointeur de type void*.

Alors, déjà, comme le souligne mewtow, l'écriture de ta ligne 6 est incorrecte, mais ce n'est pas le seul problème.

Il faut que tu passe par un char*unsigned char* pour pourvoir déférencer et faire de l'arithmétique de pointeur.

void *memset (void * s, int c, size_t n)
{
    unsigned char *ps = s;
    size_t i;
    for(i = 0; i < n; i++)
        ps[i] = (unsigned char)c; /* équivalent *(ps + i) = c; */

    return s;
}


edit:
répétition du post de Solidus. :-°
edit2:
manque le cast en unsigned char dans mon code. :-°
edit3:
unsigned char et pas char
normalement, c'est bon là.
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
14 juin 2011 à 14:25:14

Merci à vous tous :)

Voici ce que j'ai maintenant (compile et marche correctement) :

void * memset (void * s, int c, size_t n)
{
    unsigned char * ps = (unsigned char *) s;
    size_t i(0);

    for(i = 0; i < n; i++)
    {
        *(ps + i) = (unsigned char) c;
    }

    return s;
}


EDIT: Petite problème je pense :

int t[] = {145478, 1458758, 1421454, 14254585};
memset(t, 0, 3);

for(int i = 0; i < 4; i++)
{
    cout << t[i] << endl;
}


Ca m'affiche que seul la première case du tableau est remis à zéro.
Normalement ça devrait être les trois premières cases non ? (A cause du 3ème paramètre de la fonction).

Re-EDIT: Une petite modification et ça s'arrange :)

void * memset (void * s, int c, size_t n)
{
    unsigned char * ps = (unsigned char *) s;
    size_t i(0);

    for(i = 0; i < (n * sizeof(s)); i++)
    {
        *(ps + i) = (unsigned char) c;
    }

    return s;
}


Re-Re-EDIT: Cette solution pour faire marcher la fonction avec un tableau de int, mais pour une chaine de caractère, ça ne fonctionne plus :colere2: je comprend pas !
  • Partager sur Facebook
  • Partager sur Twitter
14 juin 2011 à 14:34:35

Citation : Olytron

Voici ce que j'ai maintenant (compile et marche correctement) :

En C++, mais pas en C.

PS : Pour être lisible, on écrit plutôt ps[i] que *(ps + i).
  • Partager sur Facebook
  • Partager sur Twitter
14 juin 2011 à 14:35:27

Salut,

Le troisième paramètre est un nombre d’octets ; d’où le cast vers char*.

memset(t, 0, 3); met les trois premiers octets à zéro (et une case occupe sûrement quatre octets). Pour modifier les 3 premières cases, on peut, par exemple, employer memset(t, 0, 3*sizeof*t);

Bonne prog,
--
Zyd.
  • Partager sur Facebook
  • Partager sur Twitter
14 juin 2011 à 14:37:25

Wola !
Attention, ta petite modification est fausse !
Elle fonctionne car sur ta machine, les pointeurs et les int font la même longueur (lexpression sizeof(s) ligne 6 donne la taille d'un pointeur).

Le paramètre n correspond au nombre d'octets, donc c'est à l'appel de la fonction qu'il faut utiliser sizeof pour convertir le nombre de cases à mettre à 0 en un nombre d'octets.
  • Partager sur Facebook
  • Partager sur Twitter
14 juin 2011 à 14:38:15

@Marc Mongenet : Oui ya juste à remplacer size_t i(0) en size_t i = 0;

Citation : zyd

Salut,

Le troisième paramètre est un nombre d’octets ; d’où le cast vers char*.

memset(t, 0, 3); met les trois premiers octets à zéro (et une case occupe sûrement quatre octets). Pour modifier les 3 premières cases, on peut, par exemple, employer memset(t, 0, 3*sizeof*t);

Bonne prog,
--
Zyd.


Citation : Solidus

Wola !
Attention, ta petite modification est fausse !
Elle fonctionne car sur ta machine, les pointeurs et les int font la même longueur.

Le paramètre n correspond au nombre d'octets, donc c'est à l'appel de la fonction qu'il faut utiliser sizeof pour convertir le nombre de cases à mettre à 0 en un nombre d'octets.


Merci, je vois voir ça :)


EDIT:

Ma fonction memset() terminée



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

void * memset (void * s, int c, size_t n)
{
    unsigned char * ps = (unsigned char *) s;
    size_t i = 0;

    for(i = 0; i < n; i++)
    {
        ps[i] = (unsigned char) c;
    }

    return s;
}

int main(void)
{
    // Test avec une chaine de caractère
    char str[] = "almost every programmer should know memset!";
    memset (str,'-',  6 * sizeof(str[0]));
    puts (str);

    // Test avec un tableau de int
    int t[] = {145478, 1458758, 1421454, 14254585};
    memset(t, 0, 3*sizeof(t[0]));

    int i = 0;
    for(i = 0; i < 4; i++)
    {
        printf("%d\n", t[i]);
    }

    return EXIT_SUCCESS;
}


Un grand merci à vous tous !
Enfin fini avec cette fonction (enfin j'espère ^^).

Et la correction :



void *
_memset (void * s, int c, size_t n) {
    char * _s = s;
    unsigned char _c = c;

    while (n--)
        *_s++ = _c;
    return s;
}


C'est beaucoup plus simple comme ça :)
  • Partager sur Facebook
  • Partager sur Twitter
20 avril 2018 à 16:37:05

Bonjour a tous !
Désolé de déterrer un si vieux sujet, mais je me voyais encore moins en cree un nouveau pour une si petite question;

Je recode egalement cette fonction et je pense avoir compris l’essentiel, mais un petit quelque chose me gene, pourquoi caster en unsigned char et pas en char ?

On vas copier notre array octet par octet, et la seul difference des deux type est "l’interprétation" du premier bit de l'octet.
De ce fait dans les deux cas les bits seront copier correctement non ?

  • Partager sur Facebook
  • Partager sur Twitter