memcpy'nin tuhaf davranışı

Oct 26 2020

İşaretsiz uzun bir tamsayıyı bayt bayt karakter tamponuna kopyalamak istiyorum. Yorumun altındaki satırı kullanırsam, arabelleğe kopyalanmaz.

    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]);
    }

Aşağıda, her bir değerle iki çalışmanın çıktısı verilmiştir:

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)

Yanıtlar

4 EricPostpischil Oct 26 2020 at 17:42

Onaltılık olarak 268435456, 10000000 16'dır . C ++ 'nız, unsigned longbellekte daha önce düşük değerli bayta sahip bir bellekteki baytları depolar , bu nedenle bu, 00 16 , 00 16 , 00 16 , 10 16 değerlerine sahip baytlar olarak bellekte depolanır .

memcpybu baytları doğru şekilde buf.

Daha sonra strlen(buf)incelediğinde bufönce boş bayt (00 16 ) bulur . Bu, karakter dizisinin bufsıfır uzunluğa sahip olduğunu gösterir , çünkü sonlandırma karakteri hemen başında görünür. Yani strlen(buf)sıfır döndürür.

Bu dönüş değeri atandığından lendöngü for (int i = 0; i < len; i++)sıfır yineleme gerçekleştirir.

Benzer şekilde, içinde cout << "Value after unsigned long int copy - buf: " << buf << endl;, bufhiçbir karakter bunun için basılır, böylece sıfır uzunlukta bir dize içerir.

5 eerorika Oct 26 2020 at 17:31

arabelleğe kopyalanmaz.

Evet öyle.

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

Gördüğünüz çıktıyı neden beklemediğiniz açık değil. 0, boş sonlandırıcı karakterin değeridir. Tamsayının en düşük bellek sırası baytı 0 ise, arabellek, boş dizgeyi temsil eden null ile sonlandırılmış dizeyi içerir. Böyle bir durumda, gördüğünüz çıktı beklenebilir. Küçük endian sistemlerde (ve ayrıca long4 bayttan daha geniş olan büyük endian sistemlerinde ) bu, 268435456 için geçerli olan, onaltılık olarak 0x10'00'00'00'dür.

Kopyaladığınız baytların boş dizeyi temsil etmesi, baytların kopyalanmadığı anlamına gelmez.