การเริ่มต้นค่า“ int * ptr = int ()” ไม่ผิดกฎหมายอย่างไร


86

รหัสต่อไปนี้ (นำมาจากที่นี่ ):

int* ptr = int();

คอมไพล์ใน Visual C ++ และค่าเริ่มต้นตัวชี้

เป็นไปได้อย่างไร? ฉันหมายถึงint()ให้วัตถุประเภทหนึ่งintและฉันไม่สามารถกำหนดให้intกับตัวชี้ได้

โค้ดข้างบนไม่ผิดกฎหมายได้อย่างไร?


ไม่ใช่คำตอบ แต่เป็นคำถามที่ดี! ฉันไม่เคยเห็นสิ่งนี้มาก่อน
Josh

6
ตั้งแต่พื้นฐานมี 'คอนสตรัค' ใน C ++, int()อัตราผลตอบแทนคุ้มค่าคุ้มค่าสร้างint(ซึ่งผมคิดว่า C ++ สิ่งที่ระบุ 03) และค่าเริ่มต้นของการมีint 0เทียบเท่ากับint *ptr = 0;
wkl

7
@EmanuelEy: ไม่ค่าคงที่จำนวนเต็มค่าศูนย์ใด ๆ สามารถใช้เป็นค่าคงที่ของพอยน์เตอร์ว่างได้ไม่ว่าจะใช้พอยน์เตอร์จริง ๆ อย่างไร
Mike Seymour

1
@MooingDuck: ฉันไม่ได้บอกว่าNULLอาจเป็นค่าที่ไม่ใช่ศูนย์ ฉันบอกว่ามันอาจเป็นค่าคงที่จำนวนเต็มศูนย์ใด ๆ ก็ได้ (ซึ่งรวมถึงint())
Mike Seymour

5
@DanielPryden นั่นคือการใช้คำว่า "วัตถุ" ซึ่งก่อนหน้านี้ฉันไม่รู้ตัว
ปุย

คำตอบ:


110

int()เป็นนิพจน์คงที่ที่มีค่าเป็น 0 ดังนั้นจึงเป็นวิธีที่ถูกต้องในการสร้างค่าคงที่ของตัวชี้ค่าว่าง ท้ายที่สุดมันเป็นเพียงวิธีการพูดที่แตกต่างกันเล็กน้อยint *ptr = NULL;


3
+1 บิตนิพจน์คงที่มีความสำคัญและขาดหายไปจากคำตอบที่ได้รับคะแนนโหวต 2 อันดับแรก
David Rodríguez - dribeas

สิ่งนี้หายไปกับ C ++ 0x หรือไม่
Neil G

@NeilG: สิ่งนี้ยังคงเหมือนเดิมใน C ++ 11 แม้ว่าตอนนี้จะมี a nullptrซึ่งคุณสามารถใช้แทน0หรือNULLในรหัสใหม่ได้
Jerry Coffin

2
@Nils: ความชัดเจนของรหัสและการประกาศเจตนาของคุณผ่านรหัส แน่นอนด้วย C ++ 11 ตอนนี้คุณต้องการใช้ nullptr เพราะมันยังทิ้งประโยชน์ของการตรวจสอบเวลาคอมไพล์เพิ่มเติมในการผสม
Jamin Grey

3
@Nils เนื่องจากเห็นได้ชัดว่า0อาจหมายถึงค่าคงที่ของตัวชี้ที่เป็นโมฆะหรือตัวเลข 0 ในขณะที่nullptrเห็นได้ชัดว่าค่าคงที่ของตัวชี้เป็นโมฆ นอกจากนี้ตามที่ Jamin กล่าวไว้มันยังมี "การตรวจสอบเวลาคอมไพล์พิเศษ" อีกด้วย พยายามคิดก่อนพิมพ์
เส้นทางไมล์

35

เนื่องจากint()ให้ผลตอบแทน0ซึ่งสามารถใช้แทนกันNULLได้ NULLตัวเองถูกกำหนดให้เป็น0ซึ่งแตกต่างจากซีซึ่งเป็นNULL(void *) 0

โปรดทราบว่านี่อาจเป็นข้อผิดพลาด:

int* ptr = int(5);

และจะยังคงใช้งานได้:

int* ptr = int(0);

0เป็นค่าคงที่พิเศษและสามารถถือเป็นค่าตัวชี้ได้ นิพจน์คงที่ที่ให้ผล0เช่น1 - 1ได้รับอนุญาตเช่นเดียวกับค่าคงที่ของตัวชี้ null


1
โปรดทราบว่าค่า NULL ของ C ไม่จำเป็นต้องมี(void *)0เช่นกัน มันเป็นเพียงการใช้งานที่กำหนดไว้ "นิพจน์คงที่จำนวนเต็มที่มีค่า 0 หรือนิพจน์ดังกล่าวส่งให้พิมพ์เป็นโมฆะ *"
Jerry Coffin

@JerryCoffin ฉันไม่เคยใช้คอมไพเลอร์ C ซึ่งกำหนดNULLเป็น(void*)0; มันเป็นเสมอ0(หรืออาจจะ0L) (แต่ตอนนั้น C90 ทำให้(void*)0ถูกกฎหมายใน C ฉันก็ใช้ C ++ อยู่แล้ว)
James Kanze

1
@JamesKanze: ใน ubuntu 11.04 และรสชาติ linux ของเราเอง libio.h ประกอบด้วย: #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)เวอร์ชันปัจจุบันของ gcc ใน ubuntu คือ 4.5 ในระบบของเราคือ 4.0
David Rodríguez - dribeas

5
" 0เป็นลิเทอรัลพิเศษ" - เพียงเพราะมันเป็นนิพจน์คงที่และมีค่าพิเศษ 0 (1-1)พิเศษไม่แพ้กันมันยังเป็นค่าคงที่ของพอยน์เตอร์ว่างด้วยเช่นint()กัน ข้อเท็จจริงของ0การเป็นตัวอักษรนั้นเพียงพอ แต่ไม่จำเป็นต้องมีเงื่อนไขที่จะเป็นนิพจน์คงที่ บางอย่างเช่นstrlen("")แม้ว่ามันจะมีค่าพิเศษ0แต่ก็ไม่ใช่นิพจน์คงที่และด้วยเหตุนี้จึงไม่ใช่ค่าคงที่ของพอยน์เตอร์ว่าง
Steve Jessop

@SteveJessop: ฉันเห็นด้วยเกี่ยวกับการแก้ไขมันเกี่ยวกับค่าคงที่0ไม่ใช่ค่า0ตามตัวอักษร
Blagovest Buyukliev

18

นิพจน์int()จะประเมินค่าเป็นจำนวนเต็มที่เริ่มต้นคงที่ซึ่งเป็นค่า 0 ค่านั้นเป็นค่าพิเศษ: ใช้เพื่อเริ่มต้นตัวชี้ไปยังสถานะ NULL


2
สิ่งนี้ขาดรายละเอียดที่สำคัญมากที่มีอยู่ในคำตอบของ Jerry: ไม่เพียงพอที่นิพจน์จะให้ค่า 0 แต่ต้องเป็นนิพจน์คงที่ด้วย สำหรับตัวอย่างตอบโต้ด้วยint f() { return 0; }นิพจน์f()จะให้ค่า 0 แต่ไม่สามารถใช้เพื่อเริ่มต้นตัวชี้ได้
David Rodríguez - น้ำลายไหล

@ DavidRodríguez-dribeas ในความเร่งรีบของฉันที่จะนำเสนอคำตอบในแง่ที่ง่ายที่สุดเท่าที่จะเป็นไปได้ฉันจึงทิ้งส่วนนั้นไว้ ฉันหวังว่ามันจะเป็นที่ยอมรับในตอนนี้
Mark Ransom

13

จาก n3290 (C ++ 03 ใช้ข้อความที่คล้ายกัน) การแปลงตัวชี้ 4.10 [conv.ptr] ย่อหน้าที่ 1 (การเน้นเป็นของฉัน):

1 ค่าคงที่พอยน์เตอร์ว่างคือค่าปริพันธ์ของนิพจน์คงที่ (5.19) ของชนิดจำนวนเต็มที่ประเมินค่าเป็นศูนย์หรือค่า prvalue ของชนิด std :: nullptr_t ค่าคงที่ของพอยน์เตอร์ว่างสามารถแปลงเป็นชนิดตัวชี้ได้ ผลลัพธ์คือค่าตัวชี้ค่าว่างของชนิดนั้นและสามารถแยกแยะได้จากค่าอื่น ๆ ของตัวชี้วัตถุหรือประเภทตัวชี้ฟังก์ชัน การแปลงดังกล่าวเรียกว่าการแปลงตัวชี้โมฆะ [... ]

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


4

int ไม่ใช่วัตถุ

ฉันเชื่อว่าสิ่งที่เกิดขึ้นที่นี่คือคุณกำลังบอกให้ int * ชี้ไปที่ที่อยู่หน่วยความจำที่กำหนดโดย int ()

ดังนั้นถ้า int () สร้าง 0 int * จะชี้ไปที่ที่อยู่หน่วยความจำ 0


1
int()แน่นอนที่สุดคือวัตถุ
Lightness Races ใน Orbit

@Tomalak: ไม่คิดว่าจะเป็น เป็นประเภทชั่วคราวที่ไม่ใช่คลาสและฉันคิดว่าฉันพูดถูกว่าสิ่งเหล่านี้ไม่ใช่วัตถุเท่าที่มาตรฐาน C ++ เกี่ยวข้อง เป็นเรื่องแปลกเล็กน้อยที่ส่วนของ "วัตถุชั่วคราว" เริ่มต้นอย่างระมัดระวังโดยพูดถึงเฉพาะจังหวะของประเภทคลาส แต่ต่อมาจะพูดถึงการอ้างอิงที่มีผลผูกพันและแน่นอนคุณสามารถเชื่อมโยงการอ้างอิงint()ได้ กำหนดint i;แล้วไม่มีคำถามiคือวัตถุ
Steve Jessop

@ สตีฟ: ฉันคาดว่าจะมีการถกเถียงกันในเรื่องนี้ว่า "ออบเจ็กต์" เป็นพื้นที่เก็บข้อมูลใน C ++ และเทมเปิลไลบรารีไม่มีที่เก็บข้อมูลใช่ไหม 1.8 / 1 ไม่ได้แสดงรายการจังหวะอย่างชัดเจน แต่รู้สึกราวกับว่ามีเจตนาที่จะรวมไว้ด้วย
Lightness Races ใน Orbit

1
@ Tomalak: ใช่แน่นอนชั่วคราวประเภทที่ไม่ใช่คลาสไม่จำเป็นต้องจัดเก็บเว้นแต่คุณจะใช้อ้างอิง ไม่เป็นไรแม้ว่ามันจะไม่สำคัญมาก คำสั่ง "well int ไม่ใช่วัตถุ" เป็นจริงเพราะintเป็นประเภทไม่ใช่วัตถุ ไม่ว่าจะint()ให้ผลตอบแทนเป็นวัตถุหรือเพียงแค่ค่า r ก็ไม่ส่งผลกระทบต่อสิ่งใด ๆ ที่ใคร ๆ กล่าวไว้
Steve Jessop

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