Apa artinya kesalahan ini? Saya tidak bisa menyelesaikannya dengan cara apa pun.
peringatan: konversi yang tidak digunakan lagi dari konstanta string ke 'char *' [-Wwrite-string]
programming
arduino-ide
c
Federico Corazza
sumber
sumber
Jawaban:
Seperti biasa saya, saya akan memberikan sedikit informasi teknis latar belakang ke mengapa dan di mana kesalahan ini.
Saya akan memeriksa empat cara berbeda menginisialisasi string C dan melihat apa perbedaan di antara mereka. Inilah empat cara yang dipertanyakan:
Sekarang untuk ini saya ingin mengubah huruf ketiga "i" menjadi "o" untuk membuatnya "Thos is some text". Itu bisa, dalam semua kasus (Anda akan berpikir), dicapai dengan:
Sekarang mari kita lihat apa yang masing-masing cara mendeklarasikan string dan bagaimana
text[2] = 'o';
pernyataan itu akan memengaruhi banyak hal.Pertama cara yang paling sering terlihat:
char *text = "This is some text";
. Apa artinya ini secara harfiah? Nah, dalam C, secara harfiah berarti "Buat variabel yang disebuttext
yang merupakan pointer baca-tulis ke string literal ini yang diadakan di ruang read-only (kode).". Jika Anda mengaktifkan opsi-Wwrite-strings
maka Anda akan mendapat peringatan seperti yang terlihat pada pertanyaan di atas.Pada dasarnya itu berarti "Peringatan: Anda telah mencoba membuat variabel yang titik baca-tulis ke area yang tidak dapat Anda tulis". Jika Anda mencoba dan kemudian mengatur karakter ketiga ke "o" Anda sebenarnya akan mencoba menulis ke area baca-saja dan semuanya tidak akan menyenangkan. Pada PC tradisional dengan Linux yang menghasilkan:
Sekarang yang kedua:
char text[] = "This is some text";
. Secara harfiah, dalam C, itu berarti "Buat array bertipe" char "dan inisialisasi dengan data" Ini adalah beberapa teks \ 0 ". Ukuran array akan cukup besar untuk menyimpan data". Sehingga sebenarnya mengalokasikan RAM dan menyalin nilai "Ini adalah beberapa teks \ 0" ke dalamnya saat runtime. Tidak ada peringatan, tidak ada kesalahan, sangat valid. Dan cara yang tepat untuk melakukannya jika Anda ingin dapat mengedit data . Mari kita coba jalankan perintahtext[2] = 'o'
:Itu bekerja dengan sempurna. Baik.
Sekarang cara ketiga:
const char *text = "This is some text";
. Lagi arti literal: "Buat variabel yang disebut" teks "yang merupakan pointer hanya baca untuk data ini dalam memori hanya baca.". Perhatikan bahwa pointer dan data sekarang hanya baca. Tidak ada kesalahan, tidak ada peringatan. Apa yang terjadi jika kita mencoba dan menjalankan perintah pengujian kita? Yah, kita tidak bisa. Kompiler sekarang cerdas dan tahu bahwa kami mencoba melakukan sesuatu yang buruk:Bahkan tidak akan dikompilasi. Mencoba menulis ke memori hanya-baca sekarang dilindungi karena kami telah memberi tahu kompiler bahwa pointer kami adalah memori hanya-baca. Tentu saja, itu tidak memiliki harus menunjuk ke memori hanya-baca, tetapi jika Anda arahkan ke baca-tulis memori (RAM) memori yang masih akan dilindungi dari yang ditulis oleh compiler.
Akhirnya bentuk terakhir:
const char text[] = "This is some text";
. Sekali lagi, seperti sebelumnya dengan[]
itu mengalokasikan array dalam RAM dan menyalin data ke dalamnya. Namun, sekarang ini adalah array baca-saja. Anda tidak dapat menulis ke sana karena penunjuknya ditandai sebagaiconst
. Mencoba menulis kepadanya menghasilkan:Jadi, ringkasan singkat dari tempat kami berada:
Formulir ini sepenuhnya tidak valid dan harus dihindari dengan cara apa pun. Ini membuka pintu bagi segala macam hal buruk yang terjadi:
Formulir ini adalah formulir yang tepat jika Anda ingin membuat data dapat diedit:
Formulir ini adalah formulir yang tepat jika Anda ingin string yang tidak akan diedit:
Bentuk ini sepertinya boros RAM tetapi memang ada kegunaannya. Lebih baik lupakan saja untuk saat ini.
sumber
PROGMEM
,PSTR()
atauF()
. Dengan demikian,const char text[]
tidak menggunakan lebih banyak RAM daripadaconst char *text
.(const char *)(...)
casting sederhana . Tidak ada efek nyata jika papan tidak membutuhkannya, tetapi penghematan besar jika Anda kemudian porting kode Anda ke papan yang tidak.Untuk menguraikan jawaban Makenko yang sangat baik, ada alasan bagus mengapa kompiler memperingatkan Anda tentang ini. Mari kita buat sketsa tes:
Kami memiliki dua variabel di sini, foo dan bar. Saya memodifikasi salah satu yang ada di setup (), tetapi lihat hasilnya:
Mereka berdua berubah!
Bahkan jika kita melihat peringatan yang kita lihat:
Kompiler tahu ini cerdik, dan itu benar! Alasan untuk ini adalah, bahwa kompiler (cukup) mengharapkan konstanta string tidak berubah (karena mereka adalah konstanta). Jadi jika Anda merujuk ke konstanta string
"This is some text"
beberapa kali dalam kode Anda, itu diperbolehkan untuk mengalokasikan memori yang sama untuk semuanya. Sekarang jika Anda memodifikasi satu, Anda memodifikasi semuanya!sumber
*foo
dan*bar
menggunakan berbagai tali "konstanta" , mencegah hal ini terjadi? Juga, bagaimana ini berbeda dari tidak meletakkan string sama sekali, sepertichar *foo;
:?new
,strcpy
dandelete
).Entah berhenti mencoba meneruskan string konstan di mana fungsi mengambil
char*
, atau mengubah fungsi sehingga mengambilconst char*
alih.String seperti "string acak" adalah konstanta.
sumber
Contoh:
Peringatan:
Fungsi
foo
mengharapkan char * (yang karenanya dapat dimodifikasi) tetapi Anda melewati string literal, yang tidak boleh dimodifikasi.Compiler memperingatkan Anda untuk tidak melakukan ini. Menjadi usang itu mungkin berubah dari peringatan menjadi kesalahan dalam versi kompiler masa depan.
Solusi: Buatlah foo take a const char *:
Versi C (dan C ++) yang lebih lama memungkinkan Anda menulis kode seperti contoh saya di atas. Anda bisa membuat fungsi (seperti
foo
) yang mencetak sesuatu yang Anda berikan padanya, dan kemudian meneruskan string literal (mis.foo ("Hi there!");
)Namun fungsi yang
char *
dianggap sebagai argumen diizinkan untuk mengubah argumennya (mis. MemodifikasiHi there!
dalam kasus ini).Anda mungkin telah menulis, misalnya:
Sayangnya, dengan menurunkan literal, Anda sekarang berpotensi mengubah literal itu sehingga "Hai!" sekarang "Selamat tinggal" yang tidak baik. Bahkan jika Anda menyalin dalam string yang lebih panjang, Anda mungkin menimpa variabel lain. Atau, pada beberapa implementasi Anda akan mendapatkan pelanggaran akses karena "Hai, di sana!" mungkin dimasukkan ke dalam memori read-only (protected).
Jadi penulis kompiler secara bertahap mencela penggunaan ini, sehingga fungsi yang Anda lewatkan secara literal, harus menyatakan argumen itu sebagai
const
.sumber
can not
diubah?Saya memiliki kesalahan kompilasi ini:
Silakan ganti baris ini:
#define TIME_HEADER "T" // Header tag for serial time sync message
dengan baris ini:
#define TIME_HEADER 'T' // Header tag for serial time sync message
dan kompilasi berjalan dengan baik.
sumber