พฤติกรรมแปลก ๆ ของ memcpy

Oct 26 2020

ฉันต้องการคัดลอกจำนวนเต็มที่ยาวที่ไม่ได้ลงนามไปยังถ่านบัฟเฟอร์ไบต์โดยไบต์ ถ้าฉันใช้บรรทัดใต้ความคิดเห็นมันจะไม่ถูกคัดลอกไปยังบัฟเฟอร์

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

ต่อไปนี้คือผลลัพธ์ของการรันสองครั้งที่แต่ละค่า:

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)

คำตอบ

4 EricPostpischil Oct 26 2020 at 17:42

ในเลขฐานสิบหกเป็น 268435456 10000000 16 คุณ c ++ ร้านค้าไบต์ของนั้นunsigned longในความทรงจำกับไบต์มูลค่าต่ำก่อนหน้านี้ในหน่วยความจำดังนั้นนี้จะถูกเก็บไว้ในหน่วยความจำเป็นไบต์มีค่า 00 16 , 00 16 , 00 16 10 16

memcpybufได้อย่างถูกต้องสำเนาเหล่านี้เข้าไปในไบต์

จากนั้นเมื่อstrlen(buf)ตรวจสอบbufจะพบค่า null ไบต์ (00 16 ) ก่อน สิ่งนี้บ่งชี้ว่าสตริงอักขระbufมีความยาวเป็นศูนย์เนื่องจากอักขระยุติจะปรากฏขึ้นทันทีที่จุดเริ่มต้น จึงstrlen(buf)คืนค่าศูนย์

เนื่องจากค่าส่งคืนนี้ถูกกำหนดให้lenกับลูปจึงfor (int i = 0; i < len; i++)ทำการวนซ้ำเป็นศูนย์

ในทำนองเดียวกันในcout << "Value after unsigned long int copy - buf: " << buf << endl;, bufมีสตริงของความยาวเป็นศูนย์ดังนั้นไม่มีตัวอักษรที่พิมพ์สำหรับมัน

5 eerorika Oct 26 2020 at 17:31

ไม่ได้คัดลอกไปยังบัฟเฟอร์

ใช่แล้ว.

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

ไม่ชัดเจนว่าทำไมคุณถึงไม่คาดหวังผลลัพธ์ที่คุณเห็น 0 คือค่าของอักขระเทอร์มิเนเตอร์ null ถ้าไบต์ลำดับหน่วยความจำต่ำสุดของจำนวนเต็มคือ 0 บัฟเฟอร์จะมีสตริงที่สิ้นสุดด้วยค่าว่างที่แสดงถึงสตริงว่าง ในกรณีเช่นนี้ผลลัพธ์ที่คุณเห็นจะเป็นที่คาดหวัง ในระบบ endian ขนาดเล็ก (และในระบบ endian ขนาดใหญ่ที่longมีความกว้างมากกว่า 4 ไบต์) ซึ่งเป็นกรณีของ 268435456 ซึ่งเป็นเลขฐานสิบหก 0x10'00'00'00

เพียงเพราะไบต์ที่คุณคัดลอกแสดงถึงสตริงว่างไม่ได้หมายความว่าไบต์นั้นไม่ได้ถูกคัดลอก