Mengapa konversi dari konstanta string ke 'char *' valid dalam C tetapi tidak valid dalam C ++

163

Standar C ++ 11 (ISO / IEC 14882: 2011) mengatakan dalam § C.1.1:

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

Untuk C ++ tidak apa-apa sebagai pointer ke String Literal berbahaya karena setiap upaya untuk mengubahnya menyebabkan crash. Tetapi mengapa itu valid dalam C?

C ++ 11 juga mengatakan:

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

Yang berarti bahwa jika para pemain ditambahkan ke pernyataan pertama itu menjadi valid.

Mengapa casting membuat pernyataan kedua valid dalam C ++ dan bagaimana perbedaannya dari yang pertama? Bukankah itu masih berbahaya? Jika itu masalahnya, mengapa standar mengatakan tidak apa-apa?

rullof
sumber
3
C ++ 11 tidak memungkinkan yang pertama. Saya tidak tahu mengapa C membuat tipe string literal char[]di tempat pertama. Yang kedua adalah const_castpenyamaran.
chris
4
Terlalu banyak kode C warisan yang akan dipatahkan jika aturan ini diubah.
Paul R
1
silakan mengutip teks di mana Standar mengatakan yang kedua adalah OK.
Nawaz
13
Bahasa C memiliki string literal sebelum itu const, jadi mereka tentu tidak const.
Casey
2
C dan C ++ memungkinkan Anda untuk melakukan cast dari hampir semua tipe ke tipe lain. Itu tidak berarti gips ini bermakna dan aman.
Siyuan Ren

Jawaban:

207

Hingga C ++ 03, contoh pertama Anda valid, tetapi menggunakan konversi implisit yang sudah usang - string literal harus diperlakukan sebagai tipe char const *, karena Anda tidak dapat mengubah kontennya (tanpa menyebabkan perilaku yang tidak ditentukan).

Pada C ++ 11, konversi implisit yang telah ditinggalkan secara resmi dihapus, jadi kode yang bergantung padanya (seperti contoh pertama Anda) tidak boleh lagi dikompilasi.

Anda telah mencatat satu cara untuk memungkinkan kode untuk dikompilasi: meskipun konversi implisit telah dihapus, konversi eksplisit masih berfungsi, sehingga Anda dapat menambahkan gips. Namun, saya tidak akan menganggap ini "memperbaiki" kode.

Benar-benar memperbaiki kode memerlukan mengubah jenis pointer ke tipe yang benar:

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

Mengenai mengapa itu diizinkan dalam C ++ (dan masih dalam C): hanya karena ada banyak kode yang ada yang bergantung pada konversi implisit itu, dan memecah kode itu (setidaknya tanpa peringatan resmi) tampaknya seperti komite standar seperti ide yang buruk.

Jerry Coffin
sumber
8
@ rullof: Cukup berbahaya karena tidak memberikan fleksibilitas yang berarti, setidaknya untuk kode yang peduli (sama sekali) tentang portabilitas. Menulis ke string literal biasanya akan membuat program Anda dibatalkan pada OS modern, sehingga memungkinkan kode untuk (mencoba) menulis di sana tidak menambah fleksibilitas yang berarti.
Jerry Coffin
3
Kode snippet yang diberikan dalam jawaban ini char const *p = "abc";adalah "sah dan aman di kedua C dan C ++", bukan "sah dan aman di baik C atau C ++".
Daniel Le
4
@DanielLe kedua kalimat itu memiliki arti yang sama
Caleth
3
Oh Tuhan! [Masukkan lidah dengan kuat di pipi] Maaf, tapi "atau" adalah istilah yang benar di sini. Kode dapat dikompilasi sebagai C atau sebagai C ++, tetapi tidak dapat secara bersamaan dikompilasi sebagai C dan C ++. Anda dapat memilih salah satu, tetapi Anda harus membuat pilihan. Anda tidak dapat memiliki keduanya sekaligus. [melanjutkan operasi lidah normal].
Jerry Coffin
2
Tidak, keduanya / dan merupakan kata-kata yang paling jelas dan paling benar di sini. Entah / atau juga terjadi untuk menyampaikan makna yang benar, tetapi secara teknis tidak sejelas itu. Atau sendirian saja salah ( A atau B tidak sama dengan A dan B ).
Apollys mendukung Monica
15

Ini valid dalam C karena alasan historis. C secara tradisional menentukan bahwa jenis string literal char *lebih daripada const char *, meskipun memenuhi syarat dengan mengatakan bahwa Anda tidak benar-benar diizinkan untuk memodifikasinya.

Saat Anda menggunakan gips, Anda pada dasarnya memberi tahu kompiler bahwa Anda tahu lebih baik dari aturan pencocokan tipe default, dan itu membuat tugas OK.

Barmar
sumber
3
Itu adalah char[N]dan diubah menjadi const char[N]. Ini memiliki informasi ukuran yang melekat padanya.
chris
1
Dalam C tipe string literal adalah char[N]tetapi tidak char*eg "abc"ischar[4]
Grijesh Chauhan
2

Anda juga dapat menggunakan strdup :

char* p = strdup("abc");
baz
sumber