IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

pointeur int vers void et retour de void vers int


Sujet :

C

  1. #1
    Membre très actif Avatar de J4e8a16n
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 271
    Par défaut pointeur int vers void et retour de void vers int
    Bonjoutr à tous,


    Je ne comprends pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <stdio.h>
    #include <stdlib.h>
     
    void B(void* in2);
    void A(void* in);
     
     
    void A(void* in){
    B(  &in );
    }
     
    void B(void* in2){
    printf("%d\n", (int) ((*in2) + 2) );
    }
     
    int main(void)
    {
    int c = 2;
     
    A(&c); 
     
    return EXIT_SUCCESS;
    }
    ---------- GCC ----------
    testons5.c:
    testons5.c:13: warning: dereferencing `void *' pointer
    testons5.c:13: error: void value not ignored as it ought to be

  2. #2
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <stdio.h>
     
    static void B(void * in2)
    {
       int c = *(int*) in2;
       printf("%d\n", c + 2);
    }
     
     
    static void A(void * in)
    {
       B(in);
    }
     
     
    int main(void)
    {
       int c = 2;
     
       A(&c); 
     
       return 0;
    }

  3. #3
    Membre très actif Avatar de J4e8a16n
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 271
    Par défaut
    Citation Envoyé par nicolas.sitbon Voir le message
    Ça se lit comme

    pointeur sur cast de pointeur d'integer?

  4. #4
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    in2 est un pointeur sur void : void*
    (int *) in2 transtype (cast) la valeur de ce pointeur en un pointeur sur int : int *
    *(int*) in2 est la valeur à l'adresse (int *) in2. Cette adresse étant une adresse de int, le résultat est une valeur de type int.

  5. #5
    Membre très actif Avatar de J4e8a16n
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 271
    Par défaut
    Qui décide que c'est un int? Le fait qu'à l'origine le pointeur était un int et que la mémoire réservée est sizet = 4?

    Peut-on dire de int vers char:

    *(char*) in2; donne 4 Aha! oui
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int c = *(char*) in2;
    ...
    int c = 2;
    A(&c);
    parce que size_t char est un et size_t int est 4 (réduction)?

    ou de char vers int:

    *(int*) in2; donne 671053828 non
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int c = *(int*) in2;
    ...
    char c = 2;
    A(&c);
    Pourquoi si int>char, size_t char est un et size_t int est 4 (dilatation)?

    ou de int vers float
    *(float*) in2; donne 2 hum.... non
    ou de int vers double
    *(double*) in2; donne 2 hum.... non

    Bien vôtre et moins confusément,

  6. #6
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Citation Envoyé par J4e8a16n Voir le message
    Pourquoi si int>char, size_t char est un et size_t int est 4 (dilatation)?
    Je n'arrive pas à comprendre comment on peut parler de "dilatation" sur un forum pour le langage C...

    Bref le type "void*" est le type pointeur générique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static void useless(void * param)
    {
       int number = *(long*) param;
    }
     
    int main(void)
    {
       int number = 6;
       useless(&number);
     
       return 0;
    }
    si demain tu souhaites changer le type de number, tu conserves la même interface:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static void useless(void * param) /* <= ne change pas */
    {
       long number = *(int*) param;
    }
     
    int main(void)
    {
       long number = 6;
       useless(&number);
     
       return 0;
    }

  7. #7
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    J4e8a16n
    Qui décide que c'est un int?
    C'est toi qui l'a décidé (ou supposé ou prétendu) en faisant le cast vers un int *. Le compilateur n'a pas à se poser la question de savoir si à l'origine c'était vraiment un pointeur sur int et que 4 bytes étaient réservés. Il te croit sur parole et il t'obéit. Si tu lui donnes des informations fausses, tant pis pour toi !

    Je n'ai rien compris au reste de ton post.

  8. #8
    Membre très actif Avatar de J4e8a16n
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 271
    Par défaut
    L'int est de size_t 4 et le char de size_t 1, donc perte d'information.
    Pourquoi si je cast un un int en char l'addition fonctionnne. J'obtiens 4.

    En inverse, je cast un size_t 1 vers un size_t 4 et¸l'addition ne se fait pas. J'obtiens une adresse.

  9. #9
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    L'int est de size_t 4 et le char de size_t 1, donc perte d'information.
    Pourquoi si je cast un un int en char l'addition fonctionnne. J'obtiens 4.

    En inverse, je cast un size_t 1 vers un size_t 4 et¸l'addition ne se fait pas. J'obtiens une adresse.
    J'avoue que je ne comprend pas ce que tu veux dire. Poste un code qui met en évidence ce que tu ne comprends pas. Peut-être que je comprendrais alors ce que tu veux dire.

  10. #10
    Membre très actif Avatar de J4e8a16n
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 271
    Par défaut
    Merci pour votre réponse précédente.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    #include <stdio.h>
     
    static void A(void * in)
    {
       int up = *(int*) in;  /*  %  size_t 4*/
       printf("to int = %d\n", up * 2);
     
       int Li = *(int*) in;  /*  %    size_t  4   */
       printf("to int  = %d\n", Li * 2);
     
       char ch = *(char*) in;  /*  *  size_t 1*/
       printf("to char = %c\n\n", ch * 2);
    }
     
     
    int main(void)
    {
       int ch = 21;  /*  !  */
       char up = 37;
       long Li = 370;
     
    printf("size_t 4\n..........\n");
       A(&ch);  /*  size_t  4   */
       printf("\nsize_t 1\n............\n");
       A(&up);  /*  size_t  1   */
       A(&Li);  /*  size_t  1   */
     
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    /*  
    ---------- Compiled.exe ----------
    size_t 4
    ..........
    to int = 42
    to int  = 42
    to char = *
     
     
    size_t 1
    ............
    to int = 10826
    to int  = 10826
    to char = J
     
    to int = 740
    to int  = 740
    to char = ä    740 -256-256  =  int 228 =  ä
     
     
    Output completed (0 sec consumed)
    */
    C'est toi qui l'a décidé (ou supposé ou prétendu) en faisant le cast vers un int *. Le compilateur n'a pas à se poser la question de savoir si à l'origine c'était vraiment un pointeur sur int et que 4 bytes étaient réservés. Il te croit sur parole et il t'obéit. Si tu lui donnes des informations fausses, tant pis pour toi !
    En fin de compte, c'est ma réponse.

  11. #11
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Si je comprends bien ta question, tu trouves bizarre qu'en envoyant l'adresse d'un char à ta fonction, elle t'affiche ensuite une valeur dont la taille est supérieure à 1 octet ?

    En fait, quand tu tapes par exemple :
    En premier lieu, tu ne castes pas l'objet en lui-même mais le pointeur, puis ensuite tu déréférences. Peu importe que tu envoies à la fonction l'adresse d'un char, d'une structure, ou de n'importe quoi : si tu convertis un pointeur sur n'importe quel type vers un pointeur sur void, puis que tu convertisses ce pointeur sur void vers un pointeur sur n'importe quel type, c'est sur ce dernier type que ton programme va se baser.

    Donc, si tu envoies l'adresse d'un char à ta fonction, elle va créer un pointeur local sur void (l'objet qui est en paramètre). Ensuite, si tu castes ce pointeur sur void en pointeur sur int, puis que tu le déréférences, c'est un int que tu traites même si l'objet passé est un char. Et là, ça peut être super dangereux forcément, car plusieurs octets supplémentaires sont lus alors qu'ils ne devraient pas.
    De plus, il y a un problème de taille aussi : l'endianness. Si tu envoies l'adresse d'un char à ta fonction, et qu'elle fasse un :
    Selon le fait que ta machine soit little endian ou big endian, le résultat sera forcément différent car les octets seront lus soit dans un sens soit dans l'autre. En clair, ce n'est pas du tout portable ce genre de cast.
    Même problème si tu envoies un int et que tu castes en pointeur sur char et que tu déréférences.

    EDIT :

    D'ailleurs, voici pourquoi tu obtiens ce résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    size_t 1
    ............
    to int = 10826
    Tu envoies à ta fonction l'adresse d'un char de valeur 37 (25 en hexa), qui la caste ensuite en pointeur sur void.
    Ensuite, dans ta fonction, tu caste le pointeur sur void en pointeur sur int, puis tu déréférence. On obtient la valeur 5413 (qui, multipliée par deux, fait 10826). Or, en hexa, 5413 fait 1525.

    Valeur attendue : 0x00000025
    Valeur lue : 0x00001525

    En little endian, voici comment c'est représenté en mémoire :
    Valeur lue : 25 15 00 00

    Ce 25 hexa est la valeur que tu as envoyé à ta fonction (25 hexa = 37). Or, après le cast, elle lit 3 octets supplémentaires. Forcément, puisque tu déréférences un pointeur sur int. Or, ces 3 octets peuvent donc avoir n'importe quelle valeur ! Tu obtiens donc une valeur bidon. Voilà ce danger dont je parlais plus haut.

  12. #12
    Membre très actif Avatar de J4e8a16n
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 271
    Par défaut
    C'est en plein ça.

    À part le fait que mes neurones le sachent, y a-t-il un moyen de faire un test sur une entrée de pointeur void pour savoir de quel size_t il s'agit?

    Pour les char on peut peut-être tester le '\0' final s'il y en a un, mais sur un int . . .

  13. #13
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Citation Envoyé par J4e8a16n Voir le message
    À part le fait que mes neurones le sachent, y a-t-il un moyen de faire un test sur une entrée de pointeur void pour savoir de quel size_t il s'agit?
    Non, il n'y a aucun moyen de savoir sur quel type pointe en fait le pointeur sur void. C'est au programmeur de savoir ce qu'il fait ou de fournir cette information en plus.
    Pour les char on peut peut-être tester le '\0' final s'il y en a un, mais sur un int . .
    Pour les chaînes de caractères, on a le 0 terminal. Mais on n'a pas de moyen de savoir si le pointeur sur void pointe en fait sur une chaine de caractères ou sur autre chose. La présence d'un byte à 0 ne peut fournir cette information.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 05/04/2008, 16h07
  2. [XSLT]retour charriot xml vers html
    Par toma22 dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 29/10/2007, 19h07
  3. Retour ou non vers le répertoire d'origine.
    Par troumad dans le forum C
    Réponses: 2
    Dernier message: 18/04/2007, 17h48
  4. [Conception] Export de BDD vers Excel - Le retour
    Par Camille.CWS dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 27/02/2007, 10h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo