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 :

Écrire fonction strlcpy


Sujet :

C

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2016
    Messages : 11
    Points : 8
    Points
    8
    Par défaut Écrire fonction strlcpy
    Bonjour,

    Je dois écrire strlcpy en C, j'ai du mal à comprendre le man et je l'ai lu plusieurs fois.

    Je vous explique d'abord ce que j'ai compris, dîtes-moi si vous n'êtes pas d'accord avec moi.

    man strcpy
    Elle prend 2 paramètres, on doit copier src dans dest puis on ajoute un '\0' et on retourne dest.
    Si dest est plus courte que src alors on retourne les x caractères de src copiés dans dest.

    man strncpy
    Elle prend 3 paramètres, on doit copier les n premiers caractères de src dans dest puis on ajoute des '\0' si nécessaire quand dest est plus long que src.

    man strlcpy (ça devient compliqué)
    Elle prend 3 paramètres (char *dest, char *src, unsigned int size)
    Elle retourne la longueur qui est copiable de src dans dest.
    En parallèle, il faut copier size - 1 caractères de src dans dest et mettre un '\0' à la fin.
    La longueur retournée sera égale aux nombres de caractères, qui incluent le '\0'.
    Que doit-on retourner si dest est plus courte que src, que doit on copier dans dest ?

    Merci pour votre aide.

    [https://www.freebsd.org/cgi/man.cgi?...cpy&sektion=3]

    [http://manpagesfr.free.fr/man/man3/strcpy.3.html]

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 622
    Points
    23 622
    Par défaut
    Bonjour,

    Hélas, c'est plus rudimentaire que cela. strcpy() veut dire « String Copy » (copie de chaîne) et n'est en fait qu'une boucle qui recopie toute la chaîne pointée par src vers la destination dest jusqu'à ce qu'elle rencontre le zéro '\0' final en fin de chaîne source, mais cette fonction ne contrôle absolument pas la taille du buffer de destination, et le tout se termine en buffer overflow si jamais ça dépasse. En outre, il faut veiller à se que les chaînes ne se recouvrent pas, puisqu'on écraserait la chaîne que l'on est en train de lire. Pour cette raison, strncpy() ne peut pas non plus être utilisée pour simplement déplacer une chaîne en mémoire…

    C'est une des toutes premières fonctions définies par la norme C et qui souffre d'erreurs de jeunesse, mais que l'on ne peut corriger à cause de la compatibilité. Pour toutes ces raisons, strcpy() est aujourd'hui dépréciée.

    strncpy() a donc été définie et elle est faite pour copier au plus n caractères, zéro final compris. En fait, on l'aura compris, la plupart du temps, n est égal à la taille du buffer de destination, et cette fonction est conçue pour empêcher tout dépassement. C'est bien mais elle ne gère pas non plus les recouvrements, et copie exactement n caractères sauf si la fin de la chaîne source est rencontré avant. Si c'est le cas (et qu'il y a donc encore de la place du côté destination), la fonction terminera la chaîne proprement en lui ajoutant le '\0' mais si elle a bien pu lire n caractères valides, elle s'arrêtera là sans ajouter ce terminateur.

    Pour ces raisons, on déclare en général un buffer, on dépose '\0' dans le dernier caractère, et on passe n-1 à la fonction. De cette façon, on est presque sûr qu'il n'y aura aucun risque.

  3. #3
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Force m'est de te contredire, Obsidian : strcpy n'est en aucun cas dépréciée ni même dangereuse lorsque les préconditions d'usage sont vérifiées, sauf dans le monde chaotique des implémentations Microsoft qui se permet d'amender les normes comme bon lui semble. Cette fonction n'est pas l'équivalent de gets (qui est pour le coup fondamentalement mal conçue) pour la copie de chaînes.

    De plus :

    Citation Envoyé par Matt_Houston Voir le message
    Attention : strncpy n'est pas une version défensive de strcpy et peut produire un résultat qui n'est pas une chaîne de caractères C. On peut toutefois s'en servir comme telle sous réserve de comprendre le comportement de la fonction dans ses moindres détails. Je le reformule encore une fois : strncpy n'est pas à strcpy ce que snprintf est à sprintf.

    L'approche défensive de la copie de chaînes est implémentée par strlcpy (non standard).
    strncpy (la très mal nommée) a été conçue pour un cas d'utilisation très précis de la copie de chaînes : les noms de fichiers sous les premières versions d'Unix. Il ne faut pas s'en servir aveuglément en lieu et place de strcpy.


    Citation Envoyé par Obsidian Voir le message
    De cette façon, on est presque sûr qu'il n'y aura aucun risque.
    Je ne sais pas pour toi mais moi en programmation ça ne me suffit pas, d'être « presque sûr »..


    Citation Envoyé par tOzeurIMek Voir le message
    Que doit-on retourner si dest est plus courte que src, que doit on copier dans dest ?
    Autant de caractères qu'il est possible d'en mettre dans le buffer de destination tout en garantissant la présence d'un caractère nul à la fin, à savoir dstsize - 1 d'après la page de man que tu as mentionnée (dstsize == 0 étant un cas particulier, où la fonction ne fait rien) :

    strlcpy() copies up to dstsize - 1 characters from the string src to dst, NUL-terminating the result if dstsize is not 0.

  4. #4
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2016
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    Autant de caractères qu'il est possible d'en mettre dans le buffer de destination tout en garantissant la présence d'un caractère nul à la fin, à savoir dstsize - 1 d'après la page de man que tu as mentionnée (dstsize == 0 étant un cas particulier, où la fonction ne fait rien) :
    Bonjour à Matt_Houston et Obsidian. Merci à vous deux.

    Je suis assez d'accord avec vous sur le rôle de la fonction après sur l'aspect fonctionnel je ne suis pas assez compétent pour juger.

    Pour revenir sur la fonction strlcpy.
    prototype :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ft_strlcpy(char *dest, const char *src , size_t  n);
    Il faut copier autant de caractères de src dans dest dans la limite de n.
    On aura copié n-1 caractéres car le n caractere correspond au '\0'
    La valeur retournée sera egale à src
    Ce cas est valable si src est plus long que la valeur de n

    Si src est plus court que n :
    On aura copié tout les caracteres de src et un '\0' dans dest.
    Valeur retourner longueur src.

    J'espere ne pas avoir été trop brouillon dans mes explications, dites moi si vous d'accord avec moi ?

    Merci pour votre aide

    Est vous d'accord avec ce que j'ai dit ?

  5. #5
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    C'est à peu près cela, oui. Mais tu peux résumer plus simplement l'algorithme à :

    • si dstsize vaut zéro, alors ne rien faire ;
    • sinon, copier la chaîne source vers le buffer de destination octet par octet, jusqu'à ce que l'une au moins des conditions suivantes soit vraie :
      • le prochain caractère à copier est '\0' : on rencontre la fin de la chaîne source ;
      • le nombre de caractères copiés est dstsize moins un : on rencontre la fin du buffer de destination ;
    • terminer la chaîne copiée.


    Attention encore une fois : l'entier positif fourni à strlcpy (que tu nommes n et que la page de manuel nomme dstsize) est une taille de buffer alors que la valeur retournée par la fonction est une longueur de chaîne de caractères. Bien que les deux soient exprimées en octets, ce sont des notions à bien distinguer lorsque l'on manipule les chaînes en C.

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2016
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    Attention encore une fois : l'entier positif fourni à strlcpy (que tu nommes n et que la page de manuel nomme dstsize) est une taille de buffer alors que la valeur retournée par la fonction est une longueur de chaîne de caractères. Bien que les deux soient exprimées en octets, ce sont des notions à bien distinguer lorsque l'on manipule les chaînes en C.
    Merci pour ton explication. J'ai exactement compris ce que tu as écrit .

    Le paramètre n est une des conditions d'arrêt pour la copie de src dans dest alors que la fonction retourne la longueur de la chaîne de caractères src. Même si src n'a pas totalement été copié dans dest. Il faut renvoyer la longueur complète de src.

    Si c'est ça je me lance dans le code.

  7. #7
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Putain.. je viens de relire le man.

    Tu as tout-à-fait raison et je me souviens maintenant pourquoi je n'utilise jamais cette fonction telle quelle :

    [...] strlcpy() and strlcat() functions return the total length of the string they tried to create. For strlcpy() that means the length of src.
    Quoiqu'il arrive, la fonction parcoure l'intégralité de la chaîne d'entrée.

    Ce serait bien plus pertinent de considérer la chaîne source comme un flux de taille inconnue, donc de renvoyer le nombre de caractères copiés à la manière d'un fread. Si on cherche absolument à connaître la taille de src, alors on peut toujours effectuer un strlen.

  8. #8
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 642
    Points
    7 642
    Par défaut
    Bonjour,

    La fonction strlcpy() est basée sur la même logique que strlcat(), pour cette dernière on peut y voir l'intérêt de retourner la place qu'il nous aurait fallu
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    size_t lg = strlcat( txt , toAdd ); // on 'tente' la concaténation
    if ( lg >= sizeTxt ) {              // cas que l'on suppose très rare
       txt = realloc( txt , lg+1 );     // c'est pas safe, je sais
       memcpy( txt+sizeTxt-1 , toAdd+(lg-sizeTxt+1) ); // ajouter le manquant
       sizeTxt = lg+1;
    }

  9. #9
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Si la fonction retournait le nombre de bytes effectivement copié alors tu pourrais faire exactement la même chose en strlen-ant la chaîne à partir de l'endroit où la copie a cessé, sauf que tu aurais le choix.

  10. #10
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 642
    Points
    7 642
    Par défaut
    Mais ici, il n'y plus aucun parcours de chaîne à effectuer, si la chaîne est longue, c'est toujours un peu de CPU gagné. Et on a aussi le choix

  11. #11
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Ben non, tu n'as pas le choix : si tu essaies de copier / concaténer une chaîne de longueur i + j dans un buffer de taille i, la fonction va quoiqu'il arrive te strlen une chaîne de longueur j + 1. Si c'est justement ce que tu voulais faire ensuite, tant mieux. Sinon, deal with it.

Discussions similaires

  1. ecrire fonction arrondi sup sous VBA
    Par boom47 dans le forum Excel
    Réponses: 1
    Dernier message: 25/01/2012, 16h35
  2. Ecrire fonction trigger
    Par NGeVtC87 dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 18/02/2010, 07h59
  3. Ecrire fonction VB6
    Par nicoweb371 dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 30/11/2005, 10h44
  4. Ecrire dans un tableau html depuis une fonction js ?
    Par botanica dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 05/10/2005, 12h48
  5. [XML+XSLT+MSXML] Ecrire ses propres fonctions
    Par görgh dans le forum XSL/XSLT/XPATH
    Réponses: 6
    Dernier message: 19/05/2005, 13h04

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