comportement étrange de memcpy

Oct 26 2020

Je veux copier un entier long non signé dans le tampon de caractères octet par octet. Si j'utilise la ligne sous commentaire, elle n'est pas copiée dans la mémoire tampon.

    char buf[128];
    //unsigned long int_val = 268435456;
    unsigned long int_val = 293456376;

    cout << "Value of int_val: " << int_val << endl;

    memset(buf, 0, sizeof(buf));

    memcpy(buf, &int_val, sizeof(long));
    cout << "Value after unsigned long int copy - buf: " << buf << endl;

    const int len = strlen(buf);
    cout << "buf" << endl << "====" << endl;
    for (int i = 0; i < len; i++)
    {
        printf("%3d (0x%02X)\n", buf[i], buf[i]);
    }

Voici la sortie de deux exécutions avec chaque valeur:

Value of int_val: 268435456
Value after unsigned long int copy - buf:
buf
===

Value of int_val: 293456376
Value after unsigned long int copy - buf: ��}
buf
===
 -8 (0xFFFFFFF8)
-55 (0xFFFFFFC9)
125 (0x7D)
 17 (0x11)

Réponses

4 EricPostpischil Oct 26 2020 at 17:42

En hexadécimal, 268435456 est 10000000 16 . Votre C ++ stocke les octets d'un unsigned longen mémoire avec l'octet de faible valeur plus tôt en mémoire, de sorte qu'il est stocké en mémoire sous forme d'octets avec les valeurs 00 16 , 00 16 , 00 16 , 10 16 .

memcpycopie correctement ces octets dans buf.

Ensuite, lors de l' strlen(buf)examen buf, il trouve d'abord un octet nul (00 16 ). Cela indique que la chaîne de caractères dans bufa une longueur nulle, car le caractère de fin apparaît immédiatement au début. Donc strlen(buf)renvoie zéro.

Étant donné que cette valeur de retour est affectée à len, la boucle for (int i = 0; i < len; i++)n'effectue aucune itération.

De même, dans cout << "Value after unsigned long int copy - buf: " << buf << endl;, bufcontient une chaîne de longueur nulle, donc aucun caractère n'est imprimé pour elle.

5 eerorika Oct 26 2020 at 17:31

il n'est pas copié dans la mémoire tampon.

Oui, ça l'est.

cout << ... << buf << endl;
const int len = strlen(buf);

On ne sait pas pourquoi vous ne vous attendiez pas à la sortie que vous voyez. 0 est la valeur du caractère de terminaison nul. Si l'octet d'ordre de mémoire le plus bas de l'entier est 0, le tampon contient la chaîne terminée par null qui représente la chaîne vide. Dans ce cas, la sortie que vous voyez est à prévoir. Sur les systèmes little endian (et aussi sur les systèmes big endian où longest plus large que 4 octets) c'est le cas pour 268435456 qui est 0x10'00'00'00 en hexadécimal.

Ce n'est pas parce que les octets que vous avez copiés représentent la chaîne vide que les octets n'ont pas été copiés.