Bu hata ne anlama geliyor? Hiçbir şekilde çözemiyorum.
uyarı: dize sabitinden 'char *' a kullanımdan kaldırıldı [-Wwrite-strings]
Bu hata ne anlama geliyor? Hiçbir şekilde çözemiyorum.
uyarı: dize sabitinden 'char *' a kullanımdan kaldırıldı [-Wwrite-strings]
Yanıtlar:
Benim alışkanlık olduğu gibi, bu hatayı neden ve nerede içine arka plan teknik bilgi biraz vereceğim.
C dizelerini başlatmanın dört farklı yolunu inceleyeceğim ve aralarındaki farkların ne olduğunu göreceğim. Söz konusu dört yol şunlardır:
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";
Şimdi bunun için "i" harfini "Tho" bir metindir "haline getirmek için üçüncü harfi" o "olarak değiştirmek isteyeceğim. Bu, her durumda (düşünürsünüz) aşağıdakiler tarafından gerçekleştirilebilir:
text[2] = 'o';
Şimdi dizeyi bildirmenin her yolunun ne yaptığını ve bu text[2] = 'o';
ifadenin bir şeyi nasıl etkileyeceğini inceleyelim.
İlk en sık görülen yol: char *text = "This is some text";
. Bu kelimenin tam anlamıyla ne anlama geliyor? Aslında, C, kelimenin tam anlamıyla " text
Salt okunur (kod) alanda tutulan bu dize değişmezine bir okuma-yazma işaretçisi olarak adlandırılan bir değişken oluşturun" anlamına gelir . Seçeneği -Wwrite-strings
etkinleştirdiyseniz, yukarıdaki soruda görüldüğü gibi bir uyarı alırsınız.
Temel olarak bu "Uyarı: Yazamadığınız bir alana okuma-yazma noktası olan bir değişken yapmaya çalıştınız" anlamına gelir. Üçüncü karakteri "o" olarak ayarlamayı denerseniz, aslında salt okunur bir alana yazmaya çalışırsınız ve işler hoş olmaz. Linux ile sonuçlanan geleneksel bir bilgisayarda:
Segmentasyon hatası
Şimdi ikinci bir: char text[] = "This is some text";
. Kelimenin tam anlamıyla, C'de, "char" türünde bir dizi oluşturun ve "Bu bir metin \ 0" verileriyle başlatın. Dizinin boyutu, verileri depolayacak kadar büyük olacaktır ". Bu aslında RAM tahsis eder ve çalışma zamanında "Bu bir metin \ 0" değerini kopyalar. Uyarı yok, hata yok, mükemmel bir şekilde geçerli. Ve verileri düzenlemek istiyorsanız bunu yapmanın doğru yolu . Komutu çalıştırmayı deneyelim text[2] = 'o'
:
Thos bir metin
Mükemmel çalıştı. İyi.
Şimdi üçüncü yol: const char *text = "This is some text";
. Tekrardan anlamı: "Bu metin için salt okunur bellekte salt okunur bir işaretçi olan " metin "adlı bir değişken oluşturun ." İşaretçinin ve verilerin artık salt okunur olduğunu unutmayın. Hata yok, uyarı yok. Test komutumuzu çalıştırmayı denersek ne olur? Pekala, yapamayız. Derleyici şimdi zeki ve kötü bir şey yapmaya çalıştığımızı biliyor:
hata: salt okunur konumun atanması '* (metin + 2u)'
Derlenmeyecek bile. Salt okunur belleğe yazmaya çalışmak artık korunuyor çünkü derleyiciye işaretçimizin salt okunur bellek olduğunu söyledik. Tabii ki, değil sahip salt okunur bellek işaret edilecek, ancak bellek (RAM) okuma-yazma işaret edin eğer hafıza hala derleyici tarafından yazılan olmaktan korunmuş olacaktır.
Nihayet son şekli: const char text[] = "This is some text";
. Yine, daha önce olduğu gibi []
, RAM'de bir dizi tahsis eder ve verileri ona kopyalar. Ancak, şimdi bu salt okunur bir dizidir. İşaretçi olarak etiketlendiği için yazamazsınız const
. Yazmaya çalışmak şununla sonuçlanır:
hata: salt okunur konumun atanması '* (metin + 2u)'
Yani, nerede olduğumuzun kısa bir özeti:
Bu form tamamen geçersizdir ve her ne pahasına olursa olsun kaçınılmalıdır. Her türlü kötü şeyin kapısını açar:
char *text = "This is some text";
Verileri düzenlenebilir hale getirmek istiyorsanız bu form doğru formdur:
char text[] = "This is some text";
Düzenlenmeyecek dizeler istiyorsanız bu form doğru formdur:
const char *text = "This is some text";
Bu form RAM'i boşa harcıyor ama kullanımları var. En iyi şimdilik şimdilik unut.
const char text[] = "This is some text";
PROGMEM
, PSTR()
ya da gibi bir makro ile bildirmedikçe F()
. Böylece, const char text[]
daha fazla RAM kullanmaz const char *text
.
(const char *)(...)
döküm olarak tanımlama eğilimindedir . Tahtanın ihtiyacı yoksa gerçek bir etkisi yoktur, ancak kodunuzu bir panoya bağlarsanız büyük bir tasarruf sağlar.
Makenko'nun mükemmel cevabını detaylandırmak için, derleyicinin sizi bu konuda uyarmasının iyi bir nedeni var. Bir test çizimi yapalım:
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
Burada iki değişkenimiz var: foo ve bar. Birini değiştiriyorum setup () bunlardan , ama sonuç ne olduğunu görmek:
Thos is some text
Thos is some text
Onlar de değişti!
Aslında gördüğümüz uyarılara bakarsak:
sketch_jul14b.ino:1: warning: deprecated conversion from string constant to ‘char*’
sketch_jul14b.ino:2: warning: deprecated conversion from string constant to ‘char*’
Derleyici bunun tehlikeli olduğunu biliyor ve doğru! Bunun nedeni, derleyicinin (makul olarak) dize sabitlerinin değişmemesini beklemesidir (sabit oldukları için). Bu nedenle "This is some text"
, kodunuzda dize sabitine birçok kez başvurursanız , hepsine aynı belleği ayırmasına izin verilir . Şimdi birini değiştirirseniz, hepsini değiştirirsiniz!
*foo
ve *bar
kullanan farklı dize "sabitleri" , Bunu engellemek? : Ayrıca, nasıl gibi hiç bir dizeleri koyarak değil itibaren bu farklı char *foo;
?
new
, strcpy
ve ile delete
).
Bir işlevin a aldığı yere bir dize sabiti geçirmeye çalışmayı bırakın char*
ya da const char*
yerine bir işlev alacak şekilde değiştirin .
"Random string" gibi dize sabitlerdir.
Misal:
void foo (char * s)
{
Serial.println (s);
}
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo ("bar");
} // end of setup
void loop ()
{
} // end of loop
Uyarı:
sketch_jul14b.ino: In function ‘void setup()’:
sketch_jul14b.ino:10: warning: deprecated conversion from string constant to ‘char*’
İşlev foo
bir char * (bu nedenle değiştirebileceği) bekler, ancak değiştirilmemesi gereken bir dizgi değişmezi iletiyorsunuz.
Derleyici bunu yapmamanız konusunda sizi uyarıyor. Kullanımdan kaldırıldığında, bir uyarıdan gelecekteki derleyici sürümünde hataya dönüşebilir.
Çözüm: Foo'nun bir const char almasını sağlayın *:
void foo (const char * s)
{
Serial.println (s);
}
Anlamıyorum. Şunu musunuz edemez değiştirilebilir?
Eski C (ve C ++) sürümleri yukarıdaki örneğim gibi kod yazmanıza izin verir. foo
Aşağıya geçirdiğiniz bir şeyi yazdıran bir işlev (gibi ) yapabilir ve ardından değişmez bir dize (ör. foo ("Hi there!");
) Geçirebilirsiniz.
Ancak char *
argüman olarak alan bir fonksiyonun argümanını değiştirmesine izin verilir (yani Hi there!
, bu durumda değiştirebilir ).
Yazmış olabilirsiniz, örneğin:
void foo (char * s)
{
Serial.println (s);
strcpy (s, "Goodbye");
}
Ne yazık ki, bir değişmez değeri geçerek, potansiyel olarak şu değişmez değeri değiştirdiniz, böylece "Merhaba!" şimdi "Güle güle" ve bu iyi değil. Aslında daha uzun bir dizeye kopyaladıysanız, diğer değişkenlerin üzerine yazabilirsiniz. Veya bazı uygulamalarda erişim ihlali olur çünkü "Merhaba!" salt okunur (korumalı) RAM'e yerleştirilmiş olabilir.
Derleyici yazarlar bu kullanımı aşamalı olarak reddediyorlar , böylece bir değişmezi geçtiğiniz işlevler bu argümanı olarak bildirmelidir const
.
can not
Değiştirilmeyi mi kastediyorsun ?
Bu derleme hatası var:
TimeSerial.ino:68:29: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
if(Serial.find(TIME_HEADER)) {
^
Lütfen bu satırı değiştirin:
#define TIME_HEADER "T" // Header tag for serial time sync message
bu çizgi ile:
#define TIME_HEADER 'T' // Header tag for serial time sync message
ve derleme iyi gidiyor.