ข้อมูล "ประเภท" ของตัวชี้ที่เก็บไว้ในภาษา C คืออะไร


30

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


17
ชี้ไม่ได้เป็นตัวแปรแต่ค่า ตัวแปรถือค่า (และถ้าประเภทเป็นประเภทตัวชี้ค่านั้นเป็นตัวชี้และอาจเป็นที่อยู่ของโซนหน่วยความจำที่มีบางสิ่งที่มีความหมาย) โซนหน่วยความจำที่กำหนดสามารถใช้เพื่อเก็บค่าต่างๆของประเภทที่แตกต่างกัน
Basile Starynkevitch

29
"ที่อยู่ในรูปแบบเลขฐานสิบหก" ไม่นั่นเป็นเพียงตัวดีบักหรือบิตการจัดรูปแบบไลบรารี ด้วยอาร์กิวเมนต์เดียวกันคุณสามารถพูดได้ว่าพวกเขาอยู่ในไบนารีหรือฐานแปด
usr

คุณควรสอบถามเกี่ยวกับรูปแบบไม่ใช่ประเภทที่ดีกว่า ดังนั้นคำตอบแบบไม่มีคำตอบด้านล่าง ... (แม้ว่า Kilian จะเป็นจุด ๆ เดียว)
การแข่งขัน Lightness กับ Monica

1
ผมคิดว่าปัญหาลึกที่นี่เป็นความเข้าใจ OP ของประเภท เมื่อมาถึงมันค่าที่คุณจัดการในโปรแกรมของคุณเป็นเพียงบิตในหน่วยความจำ ประเภทคือวิธีการของโปรแกรมเมอร์ในการบอกคอมไพเลอร์ว่าจะจัดการบิตเหล่านั้นอย่างไรเมื่อมันสร้างรหัสการประกอบ
Justin Lardinois

ฉันคิดว่ามันสายเกินไปที่จะแก้ไขด้วยคำตอบทั้งหมด แต่คำถามนี้จะดีกว่านี้ถ้าคุณ จำกัด ฮาร์ดแวร์และ / หรือระบบปฏิบัติการตัวอย่างเช่น "บน x64 Linux"
hyde

คำตอบ:


64

ชนิดของตัวแปรพอยน์เตอร์คือ .. pointer

การดำเนินการที่คุณได้รับอนุญาตอย่างเป็นทางการให้ทำใน C คือการเปรียบเทียบ (กับตัวชี้อื่น ๆ หรือค่า NULL / ศูนย์พิเศษ) เพื่อเพิ่มหรือลบจำนวนเต็มหรือแปลงเป็นตัวชี้อื่น ๆ

เมื่อคุณยอมรับพฤติกรรมที่ไม่ได้กำหนดคุณสามารถดูได้ว่ามูลค่าคืออะไร มันมักจะเป็นคำของเครื่องจักรสิ่งเดียวกันกับจำนวนเต็มและสามารถนำไปใช้กับชนิดจำนวนเต็มได้โดยไม่สูญเสียไป (รหัส Windows ค่อนข้างมากทำได้โดยการซ่อนพอยน์เตอร์ใน DWORD หรือ HANDLE typedefs)

มีบางสถาปัตยกรรมที่พอยน์เตอร์ไม่ง่ายเพราะหน่วยความจำไม่แบน DOS / 8086 'ใกล้' และ 'ไกล'; หน่วยความจำและช่องว่างโค้ดที่แตกต่างกันของ PIC


2
คุณยังได้รับอนุญาตให้ใช้ความแตกต่างระหว่างสองพอยp1-p2น์เตอร์ ผลลัพธ์คือค่าอินทิกรัลที่ลงชื่อ โดยเฉพาะอย่างยิ่ง&(array[i])-&(array[j]) == i-j
MSalters

13
ที่จริงแล้วการแปลงเป็นประเภทอินทิกรัลนั้นถูกระบุเช่นกันโดยเฉพาะintptr_tและuintptr_tรับประกันว่าจะ "ใหญ่พอ" สำหรับค่าตัวชี้
Matthieu M.

3
คุณสามารถขึ้นอยู่กับการแปลงให้ทำงานได้ แต่การจับคู่ระหว่างจำนวนเต็มและพอยน์เตอร์นั้นเป็นไปตามที่กำหนดไว้ (ข้อยกเว้นเพียงอย่างเดียวคือ 0 -> null และแม้จะถูกระบุก็ต่อเมื่อ 0 คือค่าคงที่ IIRC)
cHao

7
การเพิ่มตัวpระบุไปยัง printf ทำให้การแสดงตัวชี้เป็นโมฆะเป็นไปตามที่มนุษย์สามารถอ่านได้หากการดำเนินการตามพฤติกรรมใน c
dmckee

6
คำตอบนี้มีความคิดที่ถูกต้อง แต่ล้มเหลวในการเรียกร้องที่เฉพาะเจาะจง การบังคับให้ตัวชี้ประเภทที่หนึ่งไม่ได้เป็นพฤติกรรมที่ไม่ได้กำหนดและประเภทข้อมูลของ Windows HANDLE ไม่ใช่ค่าตัวชี้ (ไม่ใช่ตัวชี้ที่ซ่อนอยู่ในประเภทข้อมูลหนึ่งซึ่งเป็นจำนวนเต็มซ่อนอยู่ในประเภทตัวชี้เพื่อป้องกันการคำนวณ)
Ben Voigt

44

คุณกำลังทำอะไรที่ซับซ้อนเกินไป

ที่อยู่เป็นจำนวนเต็มเพียงช่วงเวลา โดยหลักการแล้วมันคือจำนวนเซลล์หน่วยความจำที่อ้างอิง (ในทางปฏิบัติสิ่งนี้จะมีความซับซ้อนมากขึ้นเนื่องจากเซ็กเมนต์หน่วยความจำเสมือน ฯลฯ )

ไวยากรณ์เลขฐานสิบหกเป็นนวนิยายที่สมบูรณ์ซึ่งมีอยู่เพื่อความสะดวกของโปรแกรมเมอร์เท่านั้น 0x1A และ 26 มีจำนวนเท่ากันทุกประการและไม่ใช้กับคอมพิวเตอร์ - ภายในคอมพิวเตอร์จะใช้ 00011010 เสมอ (ชุดสัญญาณไบนารี)

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


26
ที่อยู่ไม่ใช่แค่จำนวนเต็มแน่นอน เช่นเดียวกับจำนวนจุดลอยตัวที่แน่นอนที่สุดไม่ใช่แค่จำนวนเต็ม
gnasher729

8
จริง ตัวอย่างที่รู้จักกันดีที่สุดคือ Intel 8086 ซึ่งตัวชี้เป็นจำนวนเต็มสองตัว
MSalters

5
@ Rob ในหน่วยความจำแบบแบ่งตัวชี้สามารถเป็นได้ทั้งค่าเดียว (ที่อยู่เมื่อเทียบกับจุดเริ่มต้นของส่วน; ชดเชย) กับส่วนที่เป็นนัยหรือส่วน / เลือกและชดเชยคู่ (ฉันคิดว่า Intel ใช้คำว่า "selector" ฉันขี้เกียจเกินกว่าที่จะค้นหาได้) ใน 8086 เหล่านี้ถูกแทนด้วยจำนวนเต็ม 16 บิตสองตัวซึ่งรวมกันเป็นที่อยู่ทางกายภาพ 20 บิตหนึ่งรายการ (ใช่คุณสามารถระบุเซลล์หน่วยความจำเดียวกันได้หลายวิธีถ้าคุณเอียง: address = (เซกเมนต์ << 4 + ออฟเซ็ต) & 0xfffff.) สิ่งนี้จะถูกนำไปใช้ร่วมกับ x86 compatibles ทั้งหมดเมื่อทำงานในโหมดจริง
CVn

4
ในฐานะที่เป็นโปรแกรมเมอร์แอสเซมเบลอร์ระยะยาวฉันสามารถยืนยันได้ว่าหน่วยความจำของคอมพิวเตอร์ไม่มีอะไรเลยนอกจากที่ตั้งหน่วยความจำที่มีจำนวนเต็ม อย่างไรก็ตามมันเป็นวิธีการที่คุณปฏิบัติต่อพวกเขาและติดตามว่าจำนวนเต็มเหล่านั้นมีความสำคัญเพียงใด เช่นในระบบของฉันตัวเลขทศนิยม 4075876853 จะถูกเก็บเป็น x'F2F0F1F5 'ซึ่งเป็นสตริง' 2015 'ใน EBCDIC ทศนิยม 2015 จะถูกจัดเก็บเป็น 000007DF ในขณะที่ x'0002015C 'แทนทศนิยมปี 2015 ในรูปแบบทศนิยมแบบเต็ม ในฐานะที่เป็นโปรแกรมเมอร์แอสเซมเบลอร์คุณต้องติดตามสิ่งเหล่านี้ คอมไพเลอร์ใช้สำหรับภาษา HL
Steve Ives

7
ที่อยู่สามารถใส่ลงในแบบหนึ่งต่อหนึ่งการติดต่อกับจำนวนเต็ม แต่เพื่อให้ทุกอย่างสามารถอื่นบนคอมพิวเตอร์ :)
ฮอบส์

15

ตัวชี้เป็นแบบนั้น - ตัวชี้ มันไม่ใช่อย่างอื่น อย่าพยายามคิดว่ามันเป็นอย่างอื่น

ในภาษาเช่น C, C ++ และ Objective-C พอยน์เตอร์ของข้อมูลมีค่าที่เป็นไปได้สี่ประเภท:

  1. ตัวชี้สามารถเป็นที่อยู่ของวัตถุ
  2. ตัวชี้สามารถชี้ผ่านองค์ประกอบสุดท้ายของอาร์เรย์ได้
  3. ตัวชี้สามารถเป็นตัวชี้ว่างซึ่งหมายความว่ามันไม่ได้ชี้ไปที่อะไร
  4. ตัวชี้สามารถมีค่าที่ไม่แน่นอนกล่าวอีกนัยหนึ่งคือขยะและสิ่งต่าง ๆ อาจเกิดขึ้นได้ (รวมถึงสิ่งเลวร้าย) หากคุณพยายามใช้

นอกจากนี้ยังมีฟังก์ชันพอยน์เตอร์ซึ่งระบุฟังก์ชันหรือเป็นพอยน์เตอร์ฟังก์ชัน null หรือมีค่าไม่แน่นอน

ตัวชี้อื่น ๆ คือ "ตัวชี้ไปยังสมาชิก" ใน C ++ เหล่านี้ไม่ใช่ที่อยู่หน่วยความจำแน่นอนที่สุด! แต่พวกเขาระบุสมาชิกของตัวอย่างใด ๆของชั้นเรียน ใน Objective-C คุณมีตัวเลือกซึ่งก็เหมือนกับ "ตัวชี้ไปยังวิธีอินสแตนซ์ที่มีชื่อเมธอดและชื่ออาร์กิวเมนต์ที่กำหนด" เช่นเดียวกับตัวชี้สมาชิกก็ระบุทุกวิธีการของคนทุกชนชั้นตราบเท่าที่พวกเขามีลักษณะเดียวกัน

คุณสามารถตรวจสอบว่าคอมไพเลอร์เฉพาะใช้พอยน์เตอร์ แต่เป็นคำถามที่แตกต่างอย่างสิ้นเชิง


4
มีพอยน์เตอร์สำหรับฟังก์ชั่นและในพอยน์เตอร์ C ++ ให้กับสมาชิก
sdenham

พอยน์เตอร์ C ++ สำหรับสมาชิกไม่ใช่ที่อยู่หน่วยความจำใช่ไหม แน่นอนว่าพวกเขาเป็น class A { public: int num; int x; }; int A::*pmi = &A::num; A a; int n = a.*pmi;ตัวแปรpmiจะไม่ใช้มากถ้ามันไม่ได้มีอยู่หน่วยความจำคือเป็นบรรทัดสุดท้ายของการจัดทำรหัสที่อยู่ของสมาชิกnumของอินสแตนซ์ของคลาสa Aคุณสามารถส่งสิ่งนี้ไปที่intตัวชี้ธรรมดา(แม้ว่าคอมไพเลอร์อาจให้คำเตือนคุณ) และทำการตรวจสอบอีกครั้งได้สำเร็จ (พิสูจน์ว่ามันเป็นน้ำตาล syntactic สำหรับตัวชี้อื่น ๆ )
dodgethesteamroller

9

ตัวชี้เป็นรูปแบบบิตที่อยู่ (ระบุเฉพาะเพื่อวัตถุประสงค์ในการอ่านหรือเขียน) คำของหน่วยความจำใน RAM ด้วยเหตุผลทางประวัติศาสตร์และตามธรรมเนียมหน่วยของการอัพเดทคือแปดบิตหรือที่รู้จักกันในภาษาอังกฤษว่า "ไบต์" หรือในภาษาฝรั่งเศส นี่คือแพร่หลาย แต่ไม่ใช่โดยธรรมชาติ; มีขนาดอื่น ๆ อยู่

ถ้าฉันจำอย่างถูกต้องมีคอมพิวเตอร์เครื่องหนึ่งที่ใช้คำ 29 บิต; ไม่เพียง แต่นี่ไม่ใช่พลังของสองคน ฉันคิดว่านี่เป็น SILLIAC แต่บทความ Wikipedia ที่เกี่ยวข้องไม่สนับสนุนสิ่งนี้ CAN BUS ใช้ที่อยู่ 29 บิต แต่โดยที่อยู่เครือข่ายการประชุมไม่ได้ถูกอ้างถึงว่าเป็นตัวชี้แม้เมื่อพวกเขาเหมือนกันในทางปฏิบัติ

ผู้คนต่างยืนยันว่าพอยน์เตอร์เป็นจำนวนเต็ม นี่ไม่ใช่สิ่งสำคัญภายในและจำเป็น แต่ถ้าเราตีความรูปแบบบิตเป็นจำนวนเต็มคุณภาพของเลขลำดับที่เป็นประโยชน์จะทำให้เกิดการใช้งานโดยตรงมาก (และมีประสิทธิภาพในฮาร์ดแวร์ขนาดเล็ก) ของโครงสร้างเช่นสตริง ความคิดของหน่วยความจำต่อเนื่องขึ้นอยู่กับลำดับ adjacency และตำแหน่งญาติเป็นไปได้; การเปรียบเทียบจำนวนเต็มและการดำเนินการทางคณิตศาสตร์สามารถนำไปใช้อย่างมีความหมาย ด้วยเหตุนี้จึงมีความสัมพันธ์ที่แข็งแกร่งเกือบตลอดเวลาระหว่างขนาดคำสำหรับการจัดเก็บข้อมูลกับ ALU (สิ่งที่ทำเลขจำนวนเต็ม)

บางครั้งทั้งสองไม่สอดคล้องกัน ในพีซียุคแรกแอดเดรสบัสกว้าง 24 บิต


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

@hyde - อาร์กิวเมนต์ของคุณมีข้อดีอยู่ในบริบทที่คุณต้องการให้ชัดเจน แต่รูปแบบที่โดดเด่นของคอมพิวเตอร์คือคอนโทรลเลอร์ที่ฝังตัวซึ่งมหัศจรรย์เช่นหน่วยความจำเสมือนเป็นนวัตกรรมล่าสุดที่มีการใช้งาน จำกัด นอกจากนี้สิ่งที่คุณชี้ให้เห็นไม่เคยช่วยให้ OP เข้าใจพอยน์เตอร์ได้ ฉันคิดว่าบริบททางประวัติศาสตร์บางอย่างจะทำให้มันน้อยลงโดยพลการ
Peter Wone

ผมไม่ทราบว่าการพูดคุยเกี่ยวกับแรมจะช่วยให้ OP จะเข้าใจเป็นคำถามคือเฉพาะที่เกี่ยวกับสิ่งที่ตัวชี้จริงๆมี โอ้ nitpick อีกอันในตัวชี้cโดยกำหนดจุดไปยังไบต์ (สามารถร่ายได้อย่างปลอดภัยchar*เช่นสำหรับการคัดลอก / เปรียบเทียบหน่วยความจำและsizeof char==1ตามที่กำหนดโดยมาตรฐาน C) ไม่ใช่คำ (เว้นแต่ขนาดของคำ CPU เท่ากับขนาดไบต์)
hyde

สิ่งที่ตัวชี้พื้นฐานคือกุญแจแฮชสำหรับการจัดเก็บ นี่คือภาษาและแพลตฟอร์มคงที่
Peter Wone

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

6

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

ไบต์ประกอบด้วย 8 บิตคำ 2 ไบต์ (หรือ 16 บิต), คำ dword 2 (หรือ 32 บิต) และ qword 2 dwords (หรือ 64 บิต) นี่ไม่ใช่วิธีเดียวที่จะจัดเรียงบิต การจัดการ 128 บิตและ 256 บิตมักเกิดขึ้นในคำแนะนำ SIMD

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

ALU (หน่วยคำนวณเลขคณิต) ทำงานบนกลุ่มของบิตราวกับว่าพวกเขาเป็นตัวแทนจำนวนเต็ม (โดยปกติรูปแบบของสองส่วนเติมเต็ม) และ FPUs ราวกับว่าพวกเขาที่จุดลอยตัวค่า (ปกติ IEEE 754 สไตล์floatและdouble) ส่วนอื่น ๆ จะทำหน้าที่เหมือนเป็นข้อมูลที่รวบรวมมาในรูปแบบตัวละครรายการตารางคำสั่ง CPU หรือที่อยู่

บนคอมพิวเตอร์ 64 บิตโดยทั่วไปชุดของ 8 ไบต์ (64 บิต) คือที่อยู่ เราแสดงที่อยู่เหล่านี้ตามอัตภาพในรูปแบบเลขฐานสิบหก (เหมือน0xabcd1234cdef5678) แต่นั่นเป็นเพียงวิธีที่ง่ายสำหรับมนุษย์ในการอ่านรูปแบบบิต แต่ละไบต์ (8 บิต) ถูกเขียนเป็นอักขระฐานสิบหกสองตัว (เทียบเท่าอักขระฐานสิบแต่ละตัว - 0 ถึง F - หมายถึง 4 บิต)

สิ่งที่เกิดขึ้นจริง (สำหรับบางระดับจริง) คือมีบิตมักจะเก็บไว้ในทะเบียนหรือเก็บไว้ในสถานที่ใกล้เคียงในธนาคารหน่วยความจำและเราแค่พยายามอธิบายให้คนอื่น

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

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

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

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

นอกจากนี้ยังมีข้อมูลแบบอ่านอย่างเดียว (บางครั้งเก็บไว้ใน ROM ที่ไม่สามารถเขียนได้!) ปัญหาการจัดตำแหน่ง (โปรเซสเซอร์บางตัวไม่สามารถโหลดได้ double s จากหน่วยความจำเว้นแต่ว่าพวกเขาจะถูกจัดตำแหน่งในวิธีการเฉพาะหรือคำสั่ง SIMD สถาปัตยกรรมอื่น ๆ

แม้แต่รายละเอียดในระดับที่สูงกว่าก็เป็นเรื่องโกหก คอมพิวเตอร์ไม่ได้ "ผลักดัน" ไปรอบ ๆ บิตพวกมันดันไปตามแรงดันและกระแส แรงดันไฟฟ้าและกระแสไฟฟ้าเหล่านี้บางครั้งไม่ได้ทำในสิ่งที่ "ควร" ทำที่ระดับนามธรรมของบิต ชิปถูกออกแบบมาเพื่อตรวจจับข้อผิดพลาดส่วนใหญ่และแก้ไขได้โดยไม่ต้องมีระดับที่สูงขึ้นโดยไม่จำเป็นต้องรับรู้

แม้แต่เรื่องโกหก

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

ดังนั้นในระดับความซื่อสัตย์ที่เพียงพอคอมพิวเตอร์จึงใช้บิตการผลักดันและบิตเหล่านั้นจะได้รับความหมายตามวิธีการใช้งาน


3

คนทำเรื่องใหญ่ ๆ ไม่ว่าพอยน์เตอร์จะเป็นจำนวนเต็มหรือไม่ จริงๆแล้วมีคำตอบสำหรับคำถามเหล่านี้ อย่างไรก็ตามคุณจะต้องก้าวเข้าสู่ดินแดนแห่งสเปคซึ่งไม่ใช่เรื่องที่ใจอ่อน เราจะดูสเปค C ISO / IEC 9899: TC2

6.3.2.3 พอยน์เตอร์

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

  2. ประเภทตัวชี้ใด ๆ อาจถูกแปลงเป็นประเภทจำนวนเต็ม ยกเว้นตามที่ระบุไว้ก่อนหน้าผลที่ได้คือการใช้งานที่กำหนดไว้ หากไม่สามารถแสดงผลลัพธ์ในประเภทจำนวนเต็มลักษณะการทำงานจะไม่ได้กำหนด ผลลัพธ์ไม่จำเป็นต้องอยู่ในช่วงของค่าของประเภทจำนวนเต็มใด ๆ

ทีนี้สำหรับสิ่งนี้คุณจะต้องรู้ข้อกำหนดเฉพาะทั่วไป "การใช้งานที่กำหนด" หมายถึงคอมไพเลอร์เดียวทุกตัวได้รับอนุญาตให้กำหนดได้แตกต่างกัน ในความเป็นจริงคอมไพเลอร์อาจกำหนดวิธีที่แตกต่างกันขึ้นอยู่กับการตั้งค่าคอมไพเลอร์ของคุณ พฤติกรรมที่ไม่ได้กำหนดหมายความว่าคอมไพเลอร์ได้รับอนุญาตให้ทำทุกอย่างตั้งแต่การรวบรวมข้อผิดพลาดของเวลาไปจนถึงพฤติกรรมที่อธิบายไม่ได้ไปจนถึงการทำงานที่สมบูรณ์แบบ

จากนี้เราจะเห็นว่าไม่ได้ระบุฟอร์มที่จัดเก็บข้อมูลพื้นฐานนอกจากนั้นอาจมีการแปลงเป็นประเภทจำนวนเต็ม ตอนนี้มีการบอกความจริงแล้วคอมไพเลอร์ทุกดวงภายใต้ดวงอาทิตย์หมายถึงพอยน์เตอร์ภายใต้ประทุนเป็นที่อยู่จำนวนเต็ม (โดยมีกรณีพิเศษจำนวนหนึ่งซึ่งอาจแสดงเป็นจำนวนเต็ม 2 แทนเพียง 1) แต่ข้อกำหนดอนุญาตให้มีอะไรเช่น ที่อยู่เป็นสตริงตัวอักษร 10!

หากเรากรอไปข้างหน้าอย่างรวดเร็วจาก C และดูข้อมูลจำเพาะ C ++ เราจะได้ความชัดเจนมากขึ้นด้วยreinterpret_castแต่นี่เป็นภาษาที่แตกต่างดังนั้นค่าของมันสำหรับคุณอาจแตกต่างกันไป:

ISO / IEC N337: ข้อมูลจำเพาะฉบับร่าง C ++ 11 (ฉันมีแบบร่างอยู่ในมือเท่านั้น)

5.2.10 ตีความการร่ายซ้ำ

  1. พอยน์เตอร์สามารถแปลงเป็นรูปแบบอินทิกรัลใด ๆ ที่มีขนาดใหญ่พอที่จะรองรับได้ ฟังก์ชั่นการทำแผนที่มีการกำหนดใช้งาน [หมายเหตุ: มันมีจุดมุ่งหมายที่จะแปลกใจสำหรับผู้ที่รู้โครงสร้างที่อยู่ของเครื่องต้นแบบ - บันทึกย่อ] ค่าประเภท std :: nullptr_t สามารถแปลงเป็นประเภทอินทิกรัลได้ การแปลงมีความหมายและความถูกต้องเช่นเดียวกับการแปลง (void *) 0 เป็นประเภทอินทิกรัล [หมายเหตุ: reinterpret_cast ไม่สามารถใช้เพื่อแปลงค่าชนิดใด ๆ เป็นชนิด std :: nullptr_t - บันทึกย่อ]

  2. ค่าประเภทหนึ่งหรือประเภทการแจงนับสามารถแปลงเป็นตัวชี้อย่างชัดเจน ตัวชี้ที่แปลงเป็นจำนวนเต็มที่มีขนาดเพียงพอ (หากมีอยู่ในการนำไปใช้) และกลับไปเป็นชนิดตัวชี้เดียวกันจะมีค่าเดิม การแมประหว่างพอยน์เตอร์กับจำนวนเต็มไม่ได้กำหนดไว้ [หมายเหตุ: ยกเว้นตามที่อธิบายไว้ใน 3.7.4.3 ผลลัพธ์ของการแปลงดังกล่าวจะไม่เป็นค่าตัวชี้ที่ได้มาอย่างปลอดภัย - บันทึกย่อ]

อย่างที่คุณเห็นที่นี่ด้วยอีกไม่กี่ปีข้างใต้เข็มขัด C ++ พบว่ามันปลอดภัยที่จะสมมติว่ามีการจับคู่กับจำนวนเต็มดังนั้นจึงไม่มีการพูดถึงพฤติกรรมที่ไม่ได้กำหนดอีกต่อไป (แม้ว่าจะมีความขัดแย้งที่น่าสนใจระหว่างส่วนที่ 4 และ 5 กับการใช้ถ้อยคำ "ถ้ามีอยู่ในการดำเนินการ")


ตอนนี้คุณควรจะเอาอะไรไปจากสิ่งนี้?

  • การนำเสนอพอยน์เตอร์ที่แน่นอนนั้นถูกกำหนดไว้ (อันที่จริงเพียงเพื่อทำให้มันยุ่งเหยิงคอมพิวเตอร์ขนาดเล็กที่ฝังตัวบางตัวจะเป็นตัวชี้โมฆะ (เป็นโมฆะ ) 0 ซึ่งเป็นที่อยู่ 255 เพื่อรองรับเทคนิคการใช้ชื่อแทนที่อยู่ที่พวกเขาใช้) *
  • หากคุณต้องถามเกี่ยวกับการเป็นตัวแทนของพอยน์เตอร์ในหน่วยความจำคุณอาจจะไม่ได้อยู่ในตำแหน่งในอาชีพการเขียนโปรแกรมของคุณที่คุณต้องการเล่นซอกับพวกเขา

ทางออกที่ดีที่สุด: การคัดเลือกนักแสดง (char *) ข้อมูลจำเพาะ C และ C ++ เต็มไปด้วยกฎที่ระบุการจัดเก็บอาร์เรย์และโครงสร้างและทั้งคู่อนุญาตให้ส่งตัวชี้ใด ๆ ไปยังอักขระ char * ถ่านอยู่เสมอ 1 ไบต์ (ไม่รับประกันใน C แต่โดย C ++ 11 มันได้กลายเป็นส่วนหนึ่งของภาษาดังนั้นมันค่อนข้างปลอดภัยที่จะคิดว่ามันคือ 1 ไบต์ทุกที่) สิ่งนี้ช่วยให้คุณสามารถคำนวณเลขคณิตบางตัวในระดับไบต์ต่อไบต์โดยไม่ต้องใช้ความรู้จริงเพื่อทราบถึงการนำเสนอเฉพาะของพอยน์เตอร์


คุณสามารถใช้พอยน์เตอร์พอยน์เตอร์ของตัวชี้ไปยังchar *? ฉันกำลังคิดถึงเครื่องสมมุติที่มีการแยกช่องว่างสำหรับโค้ดและข้อมูล
Philip Kendall

@PhilipKendall จุดดี ฉันไม่ได้รวมส่วนหนึ่งของข้อมูลจำเพาะไว้ แต่พอยน์เตอร์ของฟังก์ชั่นถือว่าเป็นสิ่งที่แตกต่างอย่างสิ้นเชิงจากตัวชี้ข้อมูลในสเปคเพราะปัญหาที่คุณยกขึ้น พอยน์เตอร์ของสมาชิกจะได้รับการปฏิบัติแตกต่างกันไป (แต่พวกเขาก็ทำแตกต่างกันไปเช่นกัน)
Cort Ammon - Reinstate Monica

A charอยู่เสมอ 1 ไบต์ใน C การอ้างอิงจากมาตรฐาน C: "ตัวดำเนินการ sizeof ให้ขนาด (เป็นไบต์) ของตัวถูกดำเนินการ" และ "เมื่อขนาดของตัวดำเนินการถูกนำไปใช้กับตัวถูกดำเนินการที่มีประเภทถ่าน, ถ่านที่ไม่ได้ลงนาม (หรือรุ่นที่ผ่านการรับรอง) ผลลัพธ์ที่ได้คือ 1 " บางทีคุณคิดว่าไบต์ยาว 8 บิต ไม่จำเป็นต้องเป็นอย่างนั้น เพื่อให้สอดคล้องกับมาตรฐานไบต์ต้องมีอย่างน้อย 8 บิต
David Hammen

ข้อมูลจำเพาะอธิบายการแปลงระหว่างตัวชี้และประเภทจำนวนเต็ม ควรจำไว้เสมอว่า "การแปลง" ระหว่างประเภทไม่ได้หมายความถึงความเท่าเทียมกันของประเภทหรือแม้แต่การเป็นตัวแทนไบนารีของทั้งสองประเภทในหน่วยความจำจะมีรูปแบบบิตเดียวกัน (ASCII สามารถ "แปลง" เป็น EBCDIC ผู้บรรเลงบิ๊กเอนด์สามารถ "แปลง" เป็น
เอนด์

1

ในสถาปัตยกรรมส่วนใหญ่ชนิดของตัวชี้จะหยุดอยู่เมื่อพวกเขาได้รับการแปลเป็นรหัสเครื่องจักร (ยกเว้นบางที "ตัวชี้อ้วน") ดังนั้นตัวชี้ไปยังintจะแยกไม่ออกจากตัวชี้ไปที่ a doubleอย่างน้อยตัวมันเอง *

[*] แม้ว่าคุณจะยังสามารถเดาได้ตามประเภทของการใช้งานที่คุณใช้


1

สิ่งสำคัญที่ต้องเข้าใจเกี่ยวกับ C และ C ++ คือประเภทใด สิ่งที่พวกเขาทำคือการคอมไพเลอร์วิธีตีความชุดของบิต / ไบต์ ให้เริ่มต้นด้วยรหัสต่อไปนี้:

int var = -1337;

ขึ้นอยู่กับสถาปัตยกรรมจำนวนเต็มจะได้รับ 32 บิตของพื้นที่ในการจัดเก็บค่านั้น ซึ่งหมายความว่าพื้นที่ในหน่วยความจำที่เก็บ var จะมีลักษณะเช่น "11111111 11111111 11111010 11000111" หรือเป็นเลขฐานสิบหก "0xFFFFFAC7" แค่นั้นแหละ. นั่นคือทั้งหมดที่เก็บไว้ในตำแหน่งนั้น ทุกประเภททำคือบอกคอมไพเลอร์วิธีการตีความข้อมูลนั้น พอยน์เตอร์ไม่แตกต่างกัน ถ้าฉันทำอะไรเช่นนี้:

int* var_ptr = &var;   //the ampersand is telling C "get the address where var's value is located"

จากนั้นคอมไพเลอร์จะได้ตำแหน่งของ var จากนั้นเก็บที่อยู่นั้นในลักษณะเดียวกับที่ข้อมูลโค้ดแรกจะบันทึกค่า -1337 ไม่มีความแตกต่างในวิธีการจัดเก็บ แต่ในการใช้งาน ไม่สำคัญว่าฉันจะทำ var_ptr ตัวชี้ไปยัง int ถ้าคุณต้องการคุณสามารถทำได้

unsigned int var2 = *(unsigned int*)var_ptr;

สิ่งนี้จะคัดลอกค่าฐานสิบหกด้านบนของ var (0xFFFFFAC7) ไปยังตำแหน่งที่เก็บค่าของ var2 ถ้าเราจะใช้ var2 เราจะพบว่าค่านั้นจะเป็น 4294965959 ไบต์ใน var2 เหมือนกับ var แต่ค่าตัวเลขแตกต่างกัน คอมไพเลอร์ตีความมันต่างกันเพราะเราบอกว่าบิตเหล่านั้นเป็นตัวแทนของความยาวที่ไม่ได้ลงนาม คุณสามารถทำเช่นเดียวกันสำหรับค่าตัวชี้ได้เช่นกัน

unsigned int var3 = (unsigned int)var_ptr;

คุณจะต้องตีความค่าที่แสดงถึงที่อยู่ของ var ว่าเป็น int ที่ไม่ได้ลงชื่อในตัวอย่างนี้

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


1

จำนวนเต็ม.

พื้นที่ที่อยู่ในคอมพิวเตอร์นั้นมีหมายเลขตามลำดับเริ่มต้นที่ 0 และเพิ่มทีละ 1 ดังนั้นตัวชี้จะเก็บหมายเลขจำนวนเต็มซึ่งสอดคล้องกับที่อยู่ในพื้นที่ที่อยู่


1

ประเภทรวมกัน

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

ตัวแปรที่ถูกประกาศให้ถือตัวชี้ไปยังถ่านมีประเภท "ตัวชี้ไปยังถ่าน" ตัวแปรที่ถูกประกาศให้ถือตัวชี้ไปยังตัวชี้ไปยัง int มีประเภท "ตัวชี้ไปยังตัวชี้ไปยัง int"

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

ป.ล. ถ้าคุณต้องการเจาะลึกเข้าไปในประเภทลองบล็อกนี้: http://www.goodmath.org/blog/2015/05/13/expressions-and-arity-part-1/

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