ขอบเขตของตัวแปร C [ซ้ำกัน]

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

สวัสดี ฉันสับสนนิดหน่อย

char *func()
 {

    return "Hello";
 }

ในที่นี้ "Hello" คือลำดับ/อาร์เรย์ของอักขระ มันเป็นตัวแปรท้องถิ่นและจะต้องหายไปทันทีที่ฟังก์ชันกลับมา แล้วทำไมเราถึงได้ค่าที่ถูกต้องล่ะ?


person Community    schedule 27.08.2012    source แหล่งที่มา
comment
นั่นยูบีไม่ใช่เหรอ? คุณไม่ได้รับคำเตือนจากคอมไพเลอร์ของคุณเหรอ?   -  person Neel Basu    schedule 27.08.2012
comment
ไม่ ในกรณีนี้ไม่ใช่ เนื่องจากสตริงถูกจัดเก็บไว้ในที่อยู่หน่วยความจำคงที่   -  person Constantinius    schedule 27.08.2012
comment
แต่เขากำลังกลับมา char* ไม่ใช่ const char* UB ใช่ไหม   -  person Neel Basu    schedule 27.08.2012
comment
@NeelBasu ตัวอักษรสตริงไม่ได้รับการจัดสรรบนสแต็กหรือไม่   -  person    schedule 27.08.2012
comment
@Constantinius ตัวอักษร String ไม่ได้รับการจัดสรรบนสแต็กหรือไม่   -  person    schedule 27.08.2012


คำตอบ (4)


"Hello" เป็นตัวอักษรสตริงและจะมีอยู่ตลอดอายุของโปรแกรม หากต้องการอ้างอิงส่วนที่เกี่ยวข้องของมาตรฐาน C99:

  • 6.4.5 ตัวอักษรสตริง

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

  • 6.2.4 ระยะเวลาในการเก็บรักษาวัตถุ

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

ค่าที่ส่งกลับของฟังก์ชันควรเป็น const char* เนื่องจากความพยายามในการแก้ไขตัวอักษรสตริงเป็นพฤติกรรมที่ไม่ได้กำหนดไว้

person hmjd    schedule 27.08.2012
comment
ตัวอักษร Strin ไม่ได้เก็บไว้ในสแต็กหรือไม่ พวกเขาจัดสรรจากฮีปหรือไม่? - person ; 27.08.2012
comment
@GreatCoder พวกเขาถูกจัดสรรในหน่วยความจำแบบอ่านอย่างเดียวซึ่งอาจเรียกว่า .rodata หรือ linker-gibberish ที่คล้ายกัน - person Lundin; 27.08.2012
comment
@GreatCoder พวกมันจะไม่ถูกเก็บไว้ในสแต็กหรือฮีป พวกเขาจะถูกรวบรวมโดยตรงในไบนารี่ที่ผลิต ฉัน คิดว่า ขอบเขตของไบนารี่ที่ใช้รวบรวมตัวอักษรสตริงนั้นมีชื่อว่า พื้นที่ข้อมูล - person hmjd; 27.08.2012
comment
@hmjd โดยทั่วไปแล้วตัวเชื่อมโยงจะมีหนึ่งเซ็กเมนต์ .data และหนึ่งเซ็กเมนต์ .rodata โดยที่ส่วนแรกมีไว้สำหรับตัวแปรระยะเวลาการจัดเก็บข้อมูลแบบคงที่ทั้งหมด (ที่ไม่ได้เตรียมใช้งานเป็นศูนย์ ซึ่งอยู่ใน .bss) และส่วนหลังใช้สำหรับตัวแปรแบบอ่านอย่างเดียว เช่น ค่าคงที่ และตัวอักษรสตริง - person Lundin; 27.08.2012
comment
@ลุนดิน ขอบคุณ ฉันรู้จักทั้งสองส่วน (เริ่มต้นและไม่ใช่) แต่ไม่รู้ชื่อ - person hmjd; 27.08.2012
comment
วิธีคิดวิธีหนึ่งคือการพิจารณาสตริงตัวอักษร เช่น "a" ให้เทียบเท่ากับการประกาศ static const char string_a[] = {'a', '\0'}; และการใช้ "a" ทั้งหมดจะถูกแทนที่ด้วย string_a ทั่วโลก โดยที่การชนกันอาจจะถูกยุบด้วยเช่นกัน - person unwind; 27.08.2012

มีความคงที่และมีที่อยู่คงที่ในหน่วยความจำ

person nshy    schedule 27.08.2012
comment
ยังไง ? เขาไม่เคยระบุ const - person Neel Basu; 27.08.2012
comment
@NeelBasu ตกลง มันเป็นสตริงตัวอักษรที่แม่นยำยิ่งขึ้น - person nshy; 27.08.2012
comment
มันเป็นกรณีของสตริงลิเทอรัลเสมอ - person Hicham; 27.08.2012

ฟังก์ชันจะทำลายค่าหลังจากส่งคืนตัวควบคุมแล้วเท่านั้น

ดังนั้น เมื่อถึงเวลาที่คำสั่งส่งคืนถูกพบ "Hello" จะถูกวางไว้เพื่อส่งคืนค่า จากนั้นฟังก์ชันจะทำลายขอบเขต

person vivek_jonam    schedule 27.08.2012
comment
จากนั้นมันควรจะพังตอนรันไทม์ คำถามที่กล่าวถึง แล้วทำไมเราถึงได้ค่าที่ถูกต้อง - person Neel Basu; 27.08.2012
comment
คุณไม่ถูกต้องเนื่องจากสตริงลิเทอรัลไม่ใช่ตัวแปรในเครื่อง (อัตโนมัติ) และไม่ได้จัดสรรบนสแต็ก แต่เป็นหน่วยความจำแบบอ่านอย่างเดียวคงที่และคงที่ - person Lundin; 27.08.2012

ดูสิ่งนี้: กำลังกลับมา ที่อยู่ตัวอักษรสตริงจากฟังก์ชันที่ปลอดภัยและพกพาได้?

แม้ว่าสตริงจะถูกลบไปแล้ว (ตัวแปรโลคัลหรือการจัดสรรไดนามิกด้วย malloc() และ free()) เมื่อคุณส่งคืนพอยน์เตอร์ ค่าก็อาจถูกต้องได้ แต่นี่เป็นพฤติกรรมที่ไม่ชัดเจน

person Hicham    schedule 27.08.2012