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]
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]
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:
char *text = "This is some text";
char text[] = "This is some text";
const char *text = "This is some text";
const char text[] = "This is some text";
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:
text[2] = 'o';
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 disebut text
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:
Kesalahan Segmentasi
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 perintah text[2] = 'o'
:
Ini adalah beberapa teks
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:
galat: penetapan lokasi hanya-baca '* (teks + 2u)'
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 sebagai const
. Mencoba menulis kepadanya menghasilkan:
galat: penetapan lokasi hanya-baca '* (teks + 2u)'
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:
char *text = "This is some text";
Formulir ini adalah formulir yang tepat jika Anda ingin membuat data dapat diedit:
char text[] = "This is some text";
Formulir ini adalah formulir yang tepat jika Anda ingin string yang tidak akan diedit:
const char *text = "This is some text";
Bentuk ini sepertinya boros RAM tetapi memang ada kegunaannya. Lebih baik lupakan saja untuk saat ini.
const char text[] = "This is some text";
PROGMEM
, PSTR()
atau F()
. Dengan demikian, const char text[]
tidak menggunakan lebih banyak RAM daripada const 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:
char *foo = "This is some text";
char *bar = "This is some text";
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo [2] = 'o'; // change foo only
Serial.println (foo);
Serial.println (bar);
} // end of setup
void loop ()
{
} // end of loop
Kami memiliki dua variabel di sini, foo dan bar. Saya memodifikasi salah satu yang ada di setup (), tetapi lihat hasilnya:
Thos is some text
Thos is some text
Mereka berdua berubah!
Bahkan jika kita melihat peringatan yang kita lihat:
sketch_jul14b.ino:1: warning: deprecated conversion from string constant to ‘char*’
sketch_jul14b.ino:2: warning: deprecated conversion from string constant to ‘char*’
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!
*foo
dan *bar
menggunakan berbagai tali "konstanta" , mencegah hal ini terjadi? Juga, bagaimana ini berbeda dari tidak meletakkan string sama sekali, seperti char *foo;
:?
new
, strcpy
dan delete
).
Entah berhenti mencoba meneruskan string konstan di mana fungsi mengambil char*
, atau mengubah fungsi sehingga mengambil const char*
alih.
String seperti "string acak" adalah konstanta.
Contoh:
void foo (char * s)
{
Serial.println (s);
}
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo ("bar");
} // end of setup
void loop ()
{
} // end of loop
Peringatan:
sketch_jul14b.ino: In function ‘void setup()’:
sketch_jul14b.ino:10: warning: deprecated conversion from string constant to ‘char*’
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 *:
void foo (const char * s)
{
Serial.println (s);
}
Saya tidak mengerti. Maksud Anda tidak dapat dimodifikasi?
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. Memodifikasi Hi there!
dalam kasus ini).
Anda mungkin telah menulis, misalnya:
void foo (char * s)
{
Serial.println (s);
strcpy (s, "Goodbye");
}
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
.
can not
diubah?
Saya memiliki kesalahan kompilasi ini:
TimeSerial.ino:68:29: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
if(Serial.find(TIME_HEADER)) {
^
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.