ฉันจะตีความคำถามของคุณเป็นสองคำถาม: 1) ทำไม->
ถึงมีอยู่และ 2) เหตุใดจึง.
ไม่อ่านตัวชี้โดยอัตโนมัติ คำตอบของคำถามทั้งสองนั้นมีรากฐานทางประวัติศาสตร์
ทำไม->
ถึงมีอยู่จริง?
ในหนึ่งในภาษา C รุ่นแรก (ซึ่งฉันจะเรียกว่า CRM สำหรับ " คู่มืออ้างอิง C " ซึ่งมาพร้อมกับรุ่นที่ 6 Unix ในเดือนพฤษภาคมปี 1975) ผู้ประกอบการ->
มีความหมายที่พิเศษมากไม่เหมือนกัน*
และ.
ผสมผสานกัน
ภาษา C ที่อธิบายโดย CRM นั้นแตกต่างจาก C สมัยใหม่อย่างมากหลายประการ ในสมาชิก struct CRM นำแนวคิดสากลของการชดเชยไบต์ซึ่งสามารถเพิ่มไปยังค่าที่อยู่ใด ๆ โดยไม่มีข้อ จำกัด ประเภท คือชื่อทั้งหมดของสมาชิก struct ทั้งหมดมีความหมายระดับโลกที่เป็นอิสระ (และดังนั้นจึงต้องไม่ซ้ำกัน) ตัวอย่างเช่นคุณสามารถประกาศ
struct S {
int a;
int b;
};
และชื่อa
จะหมายถึงออฟเซ็ต 0 ในขณะที่ชื่อb
จะย่อมาจากออฟเซ็ต 2 (สมมติว่าเป็นint
ประเภทของขนาด 2 และไม่มีการเว้นวรรค) ภาษาที่ต้องการสมาชิกทั้งหมดของ structs ทั้งหมดในหน่วยการแปลอาจมีชื่อเฉพาะหรือยืนสำหรับค่าออฟเซ็ตเดียวกัน เช่นในหน่วยการแปลเดียวกันคุณสามารถประกาศเพิ่มเติมได้
struct X {
int a;
int x;
};
และนั่นก็โอเคเนื่องจากชื่อa
นั้นจะตรงข้ามกับออฟเซต 0 แต่การประกาศเพิ่มเติมนี้
struct Y {
int b;
int a;
};
จะไม่ถูกต้องอย่างเป็นทางการเนื่องจากพยายาม "กำหนดใหม่" a
เป็นออฟเซ็ต 2 และb
ออฟเซ็ต 0
และนี่คือที่ที่->
โอเปอเรเตอร์เข้ามาเนื่องจากชื่อสมาชิก struct ทุกคนมีความหมายพอเพียงทั่วโลกภาษาที่รองรับการแสดงออกเช่นนี้
int i = 5;
i->b = 42; /* Write 42 into `int` at address 7 */
100->a = 0; /* Write 0 into `int` at address 100 */
การแปลครั้งแรกถูกแปลโดยคอมไพเลอร์ว่า "รับที่อยู่5
เพิ่มออฟเซ็ต2
และกำหนด42
ให้กับint
ค่าที่ที่อยู่ผลลัพธ์" คือข้างต้นจะกำหนด42
ที่จะคุ้มค่าที่อยู่int
7
โปรดทราบว่าการใช้งานนี้->
ไม่ได้ใส่ใจเกี่ยวกับประเภทของการแสดงออกทางด้านซ้าย ด้านซ้ายมือถูกตีความว่าเป็นที่อยู่ตัวเลข rvalue (ไม่ว่าจะเป็นตัวชี้หรือจำนวนเต็ม)
กลอุบายแบบนี้เป็นไปไม่ได้ด้วย*
และ.
ผสมผสาน คุณทำไม่ได้
(*i).b = 42;
เนื่องจาก*i
เป็นนิพจน์ที่ไม่ถูกต้องอยู่แล้ว ตัว*
ดำเนินการเนื่องจากถูกแยกจากจะ.
กำหนดข้อกำหนดชนิดที่เข้มงวดมากขึ้นบนตัวถูกดำเนินการ เพื่อให้ความสามารถในการแก้ไขข้อ จำกัด นี้ CRM แนะนำ->
ผู้ประกอบการซึ่งเป็นอิสระจากประเภทของตัวถูกดำเนินการทางซ้าย
ดังที่ Keith ระบุไว้ในความคิดเห็นความแตกต่างระหว่าง->
และชุดค่าผสม*
+ .
นี้คือสิ่งที่ CRM อ้างถึงว่า "การผ่อนคลายข้อกำหนด" ใน 7.1.8: ยกเว้นการผ่อนคลายข้อกำหนดที่E1
เป็นประเภทตัวชี้การแสดงออกE1−>MOS
นั้นเทียบเท่ากับ(*E1).MOS
ต่อมาใน K&R C คุณสมบัติหลายอย่างที่อธิบายไว้ใน CRM ได้รับการทำใหม่อย่างมีนัยสำคัญ แนวคิดของ "struct member เป็น global identifier" ถูกลบออกอย่างสมบูรณ์ และฟังก์ชั่นการใช้งานของ->
ผู้ปฏิบัติงานก็เหมือนกันกับฟังก์ชั่น*
และการ.
รวมกัน
เหตุใดจึงไม่.
อ่านตัวชี้โดยอัตโนมัติได้
อีกครั้งในรุ่น CRM ของภาษาถูกดำเนินการด้านซ้ายของ.
ผู้ประกอบการจะต้องเป็นlvalue นั่นเป็นข้อกำหนดเพียงข้อเดียวที่กำหนดไว้ในตัวถูกดำเนินการ (และนั่นคือสิ่งที่ทำให้แตกต่างจาก->
ที่อธิบายไว้ข้างต้น) โปรดทราบว่า CRM ไม่ต้องการให้ตัวถูกดำเนินการด้านซ้าย.
มีประเภท struct มันแค่ต้องการให้มันเป็น lvalue, lvalue ใด ๆ ซึ่งหมายความว่าในรุ่น CRM ของ C คุณสามารถเขียนโค้ดแบบนี้ได้
struct S { int a, b; };
struct T { float x, y, z; };
struct T c;
c.b = 55;
ในกรณีนี้คอมไพเลอร์จะเขียน55
เป็นint
มูลค่าในตำแหน่งที่ไบต์ชดเชยที่ 2 ในบล็อกหน่วยความจำอย่างต่อเนื่องที่รู้จักในฐานะc
แม้ว่าประเภทได้ข้อมูลไม่มีชื่อstruct T
b
คอมไพเลอร์จะไม่สนใจเกี่ยวกับชนิดที่แท้จริงของc
เลย สิ่งที่มันสนใจก็c
คือ lvalue: บล็อกหน่วยความจำที่เขียนได้บางประเภท
ตอนนี้ทราบว่าถ้าคุณทำเช่นนี้
S *s;
...
s.b = 42;
รหัสจะถือว่าถูกต้อง (เนื่องจากs
ยังเป็น lvalue) และคอมไพเลอร์จะพยายามเขียนข้อมูลลงในตัวชี้s
ด้วยตัวเองที่ byte-offset 2 ไม่จำเป็นต้องพูดสิ่งต่าง ๆ เช่นนี้อาจส่งผลให้หน่วยความจำล้น แต่ภาษา ไม่ได้กังวลกับเรื่องดังกล่าว
นั่นคือภาษาที่คุณเสนอเกี่ยวกับการใช้งานมากเกินไป.
สำหรับตัวชี้ประเภทนั้นจะไม่ทำงาน: โอเปอเรเตอร์.
มีความหมายเฉพาะเจาะจงมากเมื่อใช้กับพอยน์เตอร์ (ที่มีพอยน์เตอร์ lvalue หรือ lvalues ใด ๆ เลย) มันเป็นฟังก์ชั่นที่แปลกมากอย่างไม่ต้องสงสัย แต่มันอยู่ที่นั่นในเวลา
แน่นอนว่าฟังก์ชั่นแปลก ๆ นี้ไม่ได้เป็นเหตุผลที่ดีนักในการแนะนำตัว.
ดำเนินการโอเวอร์โหลดสำหรับตัวชี้ (ตามที่คุณแนะนำ) ในเวอร์ชัน C - K&R C. ที่นำกลับมาทำใหม่ แต่ยังไม่ได้ทำ บางทีในเวลานั้นอาจมีรหัสดั้งเดิมที่เขียนในเวอร์ชัน CRM ของ C ที่ต้องรองรับ
(URL สำหรับคู่มืออ้างอิง 1975 C อาจไม่เสถียรสำเนาอื่นอาจมีความแตกต่างเล็กน้อยอยู่ที่นี่ )