เหตุใดการแปลงจากค่าคงที่สตริงถึง 'char *' ใช้ได้ใน C แต่ไม่ถูกต้องใน C ++


163

มาตรฐาน C ++ 11 (ISO / IEC 14882: 2011) กล่าวใน§ C.1.1:

char* p = "abc"; // valid in C, invalid in C++

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

C ++ 11 ยังบอกด้วย:

char* p = (char*)"abc"; // OK: cast added

ซึ่งหมายความว่าหากมีการเพิ่มการร่ายลงในคำสั่งแรกมันจะใช้ได้

ทำไมการคัดเลือกนักแสดงทำให้คำสั่งที่สองใช้ได้ใน C ++ และมันแตกต่างจากคำสั่งแรกได้อย่างไร? มันยังคงเป็นอันตรายหรือไม่? ถ้าเป็นเช่นนั้นทำไมมาตรฐานถึงบอกว่าตกลง


3
C ++ 11 ไม่อนุญาตอันแรก ฉันไม่รู้ว่าทำไม C จึงสร้างสตริงตัวอักษรchar[]ขึ้นมาตั้งแต่แรก ประการที่สองคือการconst_castปลอมตัว
chris

4
มีรหัส C ดั้งเดิมมากเกินไปที่จะทำให้แตกหากกฎนี้มีการเปลี่ยนแปลง
Paul R

1
โปรดพูดข้อความที่มาตรฐานระบุว่าข้อความที่สองคือOKอะไร
นาวาซ

13
ภาษา C มีตัวอักษรของสตริงก่อนที่มันจะมีดังนั้นพวกเขาจึงจำเป็นต้องไม่ได้const const
Casey

2
C และ C ++ ช่วยให้คุณสามารถแปลงจากเกือบทุกประเภทเป็นประเภทอื่น ไม่ได้หมายความว่าการปลดเปลื้องเหล่านี้มีความหมายและปลอดภัย
Siyuan Ren

คำตอบ:


207

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

ตั้งแต่ C ++ 11 การแปลงโดยนัยที่ถูกคัดค้านนั้นถูกลบอย่างเป็นทางการดังนั้นโค้ดที่ขึ้นกับมัน (เช่นตัวอย่างแรกของคุณ) ไม่ควรรวบรวมอีกต่อไป

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

การแก้ไขรหัสอย่างแท้จริงต้องเปลี่ยนประเภทของตัวชี้เป็นชนิดที่ถูกต้อง:

char const *p = "abc"; // valid and safe in either C or C++.

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


8
@rullof: มันอันตรายพอที่จะไม่ให้ความยืดหยุ่นใด ๆ ที่มีความหมายอย่างน้อยสำหรับโค้ดที่ใส่ใจ (อย่างน้อย) เกี่ยวกับการพกพา โดยทั่วไปการเขียนตัวอักษรแบบสตริงจะทำให้โปรแกรมของคุณถูกยกเลิกในระบบปฏิบัติการที่ทันสมัยดังนั้นการอนุญาตให้เขียนโค้ด (พยายาม) เขียนนั้นจะไม่เพิ่มความยืดหยุ่นที่มีความหมายใด ๆ
Jerry Coffin

3
ข้อมูลโค้ดที่ได้รับในคำตอบนี้char const *p = "abc";คือ "ที่ถูกต้องและปลอดภัยในทั้ง C และ C ++" ไม่ได้ "ที่ถูกต้องและปลอดภัยในทั้ง C หรือ C ++"
Daniel Le

4
@DanielLe ประโยคทั้งสองนั้นมีความหมายเดียวกัน
Caleth

3
โอ้พระเจ้า! [ใส่ลิ้นอย่างแน่นหนาในแก้ม] ขออภัย แต่ "หรือ" เป็นคำที่ถูกต้องที่นี่ รหัสสามารถรวบรวมเป็น C หรือ C ++ แต่ไม่สามารถรวบรวมพร้อมกันเป็นทั้ง C และ C ++ คุณสามารถเลือกอย่างใดอย่างหนึ่ง แต่คุณต้องเลือก คุณไม่สามารถมีทั้งสองอย่างพร้อมกัน [ใช้งานลิ้นปกติต่อ]
Jerry Coffin

2
ไม่ทั้ง / และเป็นถ้อยคำที่ชัดเจนและถูกต้องที่สุดที่นี่ ทั้ง / หรือเกิดขึ้นเพื่อสื่อความหมายที่ถูกต้อง แต่ก็ไม่ชัดเจนในทางเทคนิค หรือเพียงอย่างเดียวผิดอย่างไม่อาจปฏิเสธได้ ( A หรือ Bไม่เท่ากับA และ B )
Apollys สนับสนุนโมนิก้า

15

มันถูกต้องใน C ด้วยเหตุผลทางประวัติศาสตร์ C ระบุไว้ตามเนื้อผ้าว่าชนิดของสตริงตัวอักษรchar *มากกว่าconst char *แม้ว่าจะผ่านการรับรองโดยบอกว่าคุณไม่ได้รับอนุญาตให้แก้ไข

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


3
มันเป็นและก็เปลี่ยนไปchar[N] const char[N]มีข้อมูลขนาดแนบอยู่
chris

1
ในประเภท C ของตัวอักษรสตริงchar[N]แต่ไม่ใช่char*เช่น"abc"นั้นchar[4]
Grijesh Chauhan

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