กำหนดโครงสร้างหนึ่งให้กับโครงสร้างอื่นใน C.


146

คุณสามารถกำหนดหนึ่งอินสแตนซ์ของโครงสร้างให้กับอีกคนหนึ่งได้เช่น:

struct Test t1;
struct Test t2;
t2 = t1;

ฉันเคยเห็นมันใช้งานได้กับโครงสร้างที่เรียบง่าย แต่ bu ทำงานกับโครงสร้างที่ซับซ้อนได้หรือไม่
คอมไพเลอร์รู้วิธีการคัดลอกรายการข้อมูลอย่างไรโดยขึ้นอยู่กับประเภทของมันเช่นการแยกแยะระหว่างintสตริงและสตริง

คำตอบ:


151

ใช่ถ้าโครงสร้างเป็นประเภทเดียวกัน คิดว่าเป็นสำเนาหน่วยความจำ


72
โปรดทราบว่าไม่มีการคัดลอกแบบลึกชี้ไปที่หน่วยความจำจะไม่ถูกคัดลอก
Georg Schölly

3
เห็นพ้องด้วยเป็นปัญหาที่นี่
Tim Post

16
@Tim Concurrency ไม่มีปัญหามากไปกว่าการกำหนดประเภทบิวด์อินเช่นจำนวนเต็มและคู่ - การกำหนดไม่ใช่การดำเนินการปรมาณูสำหรับสิ่งเหล่านี้

2
ตกลงถ้ามีการสร้างสำเนาฉันสามารถเพิ่มหน่วยความจำในภายหลังด้วยฟรี () ได้หรือไม่
Betlista

5
@Betlista คุณไม่สามารถเพิ่มหน่วยความจำได้ฟรี () เพราะมันเป็นตัวแปรอัตโนมัติ: en.wikipedia.org/wiki/Automatic_variable
joshdoe

138

ใช่ได้รับการสนับสนุนสำหรับ structs อย่างไรก็ตามมีปัญหา:

struct S {
   char * p;
};

struct S s1, s2;
s1.p = malloc(100);
s2 = s1;

ตอนนี้พอยน์เตอร์ของ structs ทั้งสองชี้ไปที่บล็อกหน่วยความจำเดียวกัน - คอมไพเลอร์ไม่ได้คัดลอกข้อมูลชี้ไปที่ ตอนนี้มันยากที่จะรู้ว่าอินสแตนซ์ struct ซึ่งเป็นเจ้าของข้อมูล นี่คือเหตุผลที่ C ++ คิดค้นแนวคิดของโอเปอเรเตอร์ที่ผู้ใช้กำหนดได้ - คุณสามารถเขียนรหัสเฉพาะเพื่อจัดการกับกรณีนี้


1
ฉันเพิ่มมันเพราะการอ่านมันทำให้ฉันตระหนักถึงข้อผิดพลาด / การละเว้นในคำตอบของฉันเอง
Clifford

1
+1 สำหรับการสังเกตว่าไม่มีการคัดลอกเกิดขึ้นจริง
Tom Duckering

14
เหตุใดจึงถูกตั้งค่าสถานะเป็นสแปม มีคนสูญเสียการควบคุมเมาส์ของพวกเขาหรือไม่?
Georg Fritzsche

@gf และเห็นได้ชัดว่าเป็นที่น่ารังเกียจเช่นกัน!

2
@rahmanisback คำตอบของอานนท์ค่อนข้างชัดเจนเกี่ยวกับหัวข้อนี้: "คอมไพเลอร์ไม่ได้คัดลอกข้อมูลชี้ไปที่" ข้อมูลของstructตัวเองถูกคัดลอกอย่างชัดเจน
โทเบียส

24

ดูตัวอย่างนี้ก่อน:

รหัส C สำหรับโปรแกรม C อย่างง่ายได้รับด้านล่าง

struct Foo {
    char a;
    int b;
    double c;
    } foo1,foo2;

void foo_assign(void)
{
    foo1 = foo2;
}
int main(/*char *argv[],int argc*/)
{
    foo_assign();
return 0;
}

รหัส ASM ที่เทียบเท่าสำหรับ foo_assign () คือ

00401050 <_foo_assign>:
  401050:   55                      push   %ebp
  401051:   89 e5                   mov    %esp,%ebp
  401053:   a1 20 20 40 00          mov    0x402020,%eax
  401058:   a3 30 20 40 00          mov    %eax,0x402030
  40105d:   a1 24 20 40 00          mov    0x402024,%eax
  401062:   a3 34 20 40 00          mov    %eax,0x402034
  401067:   a1 28 20 40 00          mov    0x402028,%eax
  40106c:   a3 38 20 40 00          mov    %eax,0x402038
  401071:   a1 2c 20 40 00          mov    0x40202c,%eax
  401076:   a3 3c 20 40 00          mov    %eax,0x40203c
  40107b:   5d                      pop    %ebp
  40107c:   c3                      ret    

ดังที่คุณเห็นว่าการมอบหมายงานนั้นถูกแทนที่ด้วยคำสั่ง "mov" ในชุดประกอบตัวดำเนินการกำหนดค่านั้นหมายถึงการย้ายข้อมูลจากหน่วยความจำหนึ่งไปยังตำแหน่งหน่วยความจำอื่น การมอบหมายจะทำเพื่อสมาชิกโครงสร้างทันทีและจะไม่สามารถคัดลอกได้เมื่อคุณมีประเภทข้อมูลที่ซับซ้อนในโครงสร้าง COMPLEX นี่หมายความว่าคุณไม่สามารถมีอาร์เรย์ของตัวชี้ชี้ไปที่รายการ

อาเรย์ของตัวละครภายในโครงสร้างนั้นจะไม่สามารถใช้งานได้กับคอมไพเลอร์ส่วนใหญ่เนื่องจากการมอบหมายจะพยายามคัดลอกโดยไม่ต้องดูประเภทข้อมูลที่จะเป็นประเภทที่ซับซ้อน


2
คุณสามารถอธิบายรายละเอียดเกี่ยวกับเงื่อนไขที่มันจะล้มเหลวได้ไหมเพราะดูเหมือนว่าจะทำงานให้ฉันได้เสมอ
AlphaGoku

15

นี่เป็นสำเนาที่เรียบง่ายเหมือนกับที่คุณทำmemcpy()(จริงๆแล้วคอมไพเลอร์บางคนอาจเรียกให้memcpy()ใช้รหัสนั้น) ไม่มี "สตริง" ใน C มีเพียงพอยน์เตอร์ไปยังตัวอักษรจำนวนมาก หากโครงสร้างแหล่งที่มาของคุณมีตัวชี้ดังกล่าวตัวชี้จะถูกคัดลอกไม่ใช่ตัวอักษร


ตกลงดังนั้นคอมไพเลอร์แปลสิ่งนี้เป็นให้memcpyดูที่นี่: godbolt.org/z/nPxqWc - แต่ตอนนี้ถ้าฉันผ่านพอยน์เตอร์ที่เหมือนกันaและbและ*a = *bถูกแปลmemcpyเป็นพฤติกรรมที่ไม่ได้กำหนดไว้เพราะสำหรับmemcpy"พื้นที่หน่วยความจำต้องไม่ทับซ้อนกัน" (อ้างจากหน้าคน) ดังนั้นคอมไพเลอร์ผิดในการใช้งานmemcpyหรือฉันผิดในการเขียนงานมอบหมายเช่นนี้?
ไม่ใช่ผู้ใช้

6

คุณหมายถึง "Complex" ในจำนวนเชิงซ้อนที่มีส่วนจริงและจินตภาพหรือไม่ ดูเหมือนจะไม่น่าเป็นไปได้ดังนั้นหากคุณไม่ต้องยกตัวอย่างเนื่องจาก "ซับซ้อน" หมายถึงไม่มีอะไรเฉพาะเจาะจงในแง่ของภาษา C

คุณจะได้รับสำเนาหน่วยความจำโดยตรงของโครงสร้าง ไม่ว่าจะเป็นสิ่งที่คุณต้องการขึ้นอยู่กับโครงสร้าง ตัวอย่างเช่นถ้าโครงสร้างมีตัวชี้ทั้งสองสำเนาจะชี้ไปที่ข้อมูลเดียวกัน นี่อาจเป็นหรือไม่ใช่สิ่งที่คุณต้องการ ที่ลงไปในการออกแบบโปรแกรมของคุณ

ในการทำสำเนา 'ฉลาด' (หรือสำเนา 'ลึก') คุณจะต้องใช้ฟังก์ชันเพื่อทำสำเนา นี่อาจเป็นเรื่องยากมากที่จะบรรลุหากโครงสร้างนั้นมีพอยน์เตอร์และโครงสร้างที่มีพอยน์เตอร์และอาจเป็นพอยน์เตอร์ไปยังโครงสร้างดังกล่าว (อาจเป็นสิ่งที่คุณหมายถึงโดย "ซับซ้อน") และยากต่อการบำรุงรักษา ทางออกที่ง่ายคือการใช้ C ++ และใช้ตัวสร้างการคัดลอกและตัวดำเนินการกำหนดสำหรับแต่ละโครงสร้างหรือคลาสจากนั้นแต่ละอันจะรับผิดชอบซีแมนทิกส์สำเนาของตัวเองคุณสามารถใช้ไวยากรณ์การกำหนดได้และบำรุงรักษาได้ง่ายขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.