C ++ dize sabiti 'char *' için kullanımdan kaldırıldı


154

Bir dersim var private char str[256];

ve bunun için açık bir kurucu var:

explicit myClass(const char *func)
{
    strcpy(str,func);
}

Ben şöyle diyorum:

myClass obj("example");

Bunu derlediğimde aşağıdaki uyarıyı alıyorum:

dize sabitinden 'char *' a kullanımdan kaldırıldı

Bu neden oluyor?


1
Daha güvenli bir kopya strncpy(str, func, 255)yerine kullanmalısınız strcpy(str, func). Ve sonra strncpy eklemediği için dizenin sonuna '\ 0' eklemeyi unutmayın.
Patrice Bernassola

2
Daha güvenli "strncpy (str, func, sizeof (str)); str [sizeof (str) - 1] = '\ 0';"
Warren Young

3
Ben oldukça benzer kod olurdu emin rağmen yukarıdaki alıntı, uyarı verir sanmıyorum. Anlamlı cevaplar alabilmek için, uyarıyı üreten minimal, derleyici bir örnek göndermelisiniz.
sbi

3
@Patrice, Warren: strncpy kullanma, strcpy'nin daha güvenli bir versiyonu değil. Strcpy_s kullanın (veya yeniden uygulayın).
Steve Jessop

Sorunu aldım, bu sorunları normal solaris veya ARM (hedef) yapıları için değil -X86 derlemesi için gösteriyor, bu yüzden bunu görmezden geliyorum. Örnek kodum için normalde bir uyarı göstermediği için hala bir düzeltme bulunamadı. Hepinize teşekkür ederim!
mkamthan

Yanıtlar:


144

Bu, aşağıdaki gibi bir durum olduğunda gördüğünüz bir hata iletisidir:

char* pointer_to_nonconst = "string literal";

Neden? C ve C ++ değişmez dize türünde farklılık gösterir. C tipi char dizisidir ve C ++ 'da sürekli char dizisidir. Her durumda, dizgi değişmezinin karakterlerini değiştirmenize izin verilmez, bu nedenle C ++ içindeki const gerçekten bir kısıtlama değil, bir tür güvenlik olayıdır. A dönüşüm const char*için char*güvenlik nedenleriyle açık bir dökme edilmeden bu genellikle mümkün değildir. Ancak C ile geriye doğru uyumluluk için C ++ dili, a'ya bir dize değişmez değeri atamaya izin char*verir ve size bu dönüşümün kullanımdan kaldırılması hakkında bir uyarı verir.

Yani, bir yerde constconst doğruluğu için programınızda bir veya daha fazla s eksik . Ancak bize gösterdiğiniz kod, bu tür kullanımdan kaldırılmış bir dönüşüm yapmadığı için sorun değildir. Uyarı başka bir yerden gelmiş olmalı.


17
Bu soruya ilişkin görüş ve oylar dikkate alındığında, OP'nin sorunu gerçekten gösteren bir kod sağlamadığı talihsiz bir durumdur.
Shafik Yaghmour

1
Sen silerek OP'ın kodu ile sorunu yeniden constdan MyClasssonra ekleyerek çözebilirsiniz ... yapıcısı constgeri.
Theodore Murdock

145

Uyarı:

dize sabitinden 'char *' a kullanımdan kaldırıldı

, bir yere (yayınladığınız kodda değil) benzer bir şey yaptığınız için verilir:

void foo(char* str);
foo("hello");

Sorun, bir dize hazır const char[]bilgisini (tür ile ) dönüştürmeye çalışmanızdır char*.

Dizi işaretçiye bozulduğu için bir ' const char[]yi dönüştürebilirsiniz const char*, ancak yaptığınız şey değişmez bir değişmez yapmaktır.

Bu dönüştürmeye büyük olasılıkla C uyumluluğu için izin verilir ve yalnızca size belirtilen uyarıyı verir.


96

Gibi cevap hayır. 2 by fnieto - Fernando Nieto açıkça ve doğru bir şekilde bu uyarının verildiğini açıklıyor çünkü kodunuzda bir yerde (yayınladığınız kodda değil) şöyle bir şey yapıyorsunuz:

void foo(char* str);
foo("hello");

Ancak, kodunuzu da uyarıdan uzak tutmak istiyorsanız, kodunuzda ilgili değişikliği yapmanız yeterlidir:

void foo(char* str);
foo((char *)"hello");

Yani, stringsabiti sadece (char *).


17
Alternatif olarak, işlevi yapın: void foo (const char * str)
Caprooja

3
@Caprooja Evet bu parametreyi 'sabite işaretçi' olarak bildirmek de bu durumda işe yarar. Ancak bu değişiklikle kullanıcı, uygulama bölümünde yapabileceği 'str' işaretçisini kullanarak adreste depolanan değeri değiştiremez / yeniden atayamaz. Bu, dikkat etmek isteyebileceğiniz bir şey.
sactiw

1
@sactiw Olduğu gibi kalmanın herhangi bir nedeni var void foo(char* str)mı? Bence modity olamaz düşünce striçinde foobile parametre olmayan const olarak yazılır, neyse.
kgf3JfUtW

37

3 çözüm vardır:

Çözüm 1:

const char *x = "foo bar";

Çözüm 2:

char *x = (char *)"foo bar";

Çözüm 3:

char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");

Dizi zaten sabit bir işaretçi olduğundan, işaretçiler yerine diziler de kullanılabilir.


7
Çözüm 3 için vardır strdup. Kodunuzdan farklı olarak, sonlandırıcı NUL karakteri için alan ayırır ve ayırmayı aşmaz.
Ben Voigt

2
Çözüm 2'den kaçınılmalıdır.
Yörüngedeki Hafiflik Yarışları

Aslında çözüm 2 C ++ içinde char * x = static_cast <char *> ("foo bar") olabilir.
Kehe CAI

3
Anil yorumlarınızı cevabınıza entegre edecek misiniz? Çözüm 3 hala tehlikeli bir şekilde yanlıştır.
Yörüngedeki Hafiflik Yarışları

@LightnessRacesinOrbit Lütfen bir cevap verebilir misiniz? Çözüm 2 ve 3'ten neden kaçınılması gerektiğini ve tehlikeli bir şekilde yanlış olduğunu söylediğinizi anlamıyorum.
Gladclef

4

Aslında bir dize sabit değişmezi ne const char * ne de char * değil char [] şeklindedir. Oldukça garip ama c ++ özelliklerinde yazılı; Bunu değiştirirseniz, derleyici kod kesiminde depolayabileceği için davranış tanımsızdır.


5
Const char [] olduğunu söyleyebilirim çünkü bir rvalue olarak değiştiremezsiniz.
fnieto - Fernando Nieto

3

Belki bunu deneyebilirsiniz:

void foo(const char* str) 
{
    // Do something
}

foo("Hello")

Benim için çalışıyor


2

Bu makro kodun başında bir yere ekleyerek bu sorunu çözmek. Veya içine koyun <iostream>hehe.

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())

8
"Ya da <iostream> içine ekle" Ne ?!
Yörüngedeki Hafiflik Yarışları

Düzenlenen herhangi bir nedenden ötürü ", hehe" vardı (şaka olduğunu ima etti)
Someguynamedpie

C_TEXTbir işlev çağrısı ( foo(C_TEXT("foo"));) için iyidir , ancak değer gibi bir değişkende saklanırsa tanımlanmamış davranış için ağlıyorsa char *x = C_TEXT("foo");- xişaret ettiği bellek serbest bırakıldığı için (atamanın dışında) herhangi bir kullanımı tanımlanmamış davranıştır.
Martin Bonner, Monica

1

Bu sorunun ( char* str = "some string"diğerlerinin açıkladığı sorundan daha zor algılanması daha da zor olan) bir nedeni , kullandığınız durumdur constexpr.

constexpr char* str = "some string";

Öyle görünüyor ki, daha const char* strönce olduğu gibi bir uyarıya neden olmayacak ve bu yüzden bir uyarıya neden olmayacak char*, ancak bunun gibi davranıyor gibi görünüyor char* const str.

ayrıntılar

Sabit işaretçi ve sabitin işaretçisi. Arasındaki fark const char* str, ve char* const straşağıdaki gibi açıklanabilir.

  1. const char* str: Str değerini bir const char için bir işaretçi olarak bildirin. Bu, bu işaretçinin işaret ettiği verinin sabit olduğu anlamına gelir. İşaretçi değiştirilebilir, ancak verileri değiştirme girişimleri bir derleme hatası verir.
    1. str++ ;: VALID . İşaretçiyi değiştiriyoruz, işaret eden verileri değil.
    2. *str = 'a';: GEÇERSİZ . İşaretlenen verileri değiştirmeye çalışıyoruz.
  2. char* const str: Str karakterini bir const pointer olarak bildirin. Bu, noktanın artık sabit olduğu anlamına gelir, ancak işaret edilen veriler de sabit değildir. İşaretçi değiştirilemez, ancak işaretçiyi kullanarak verileri değiştirebiliriz.
    1. str++ ;: GEÇERSİZ . Sabit olan pointer değişkenini değiştirmeye çalışıyoruz.
    2. *str = 'a';: VALID . İşaretlenen verileri değiştirmeye çalışıyoruz. Bizim durumumuzda bu bir derleme hatasına neden olmaz, ancak dize büyük olasılıkla derlenmiş ikilinin salt okunur bir bölümüne gireceğinden çalışma zamanı hatasına neden olur . Bu ifade, örneğin dinamik olarak bellek ayırmış olsaydık anlamlıdır. char* const str = new char[5];.
  3. const char* const str: Str'yi bir const char için bir const pointer olarak bildirin. Bu durumda, işaretçiyi veya işaret edilen verileri değiştiremeyiz.
    1. str++ ;: GEÇERSİZ . Sabit olan pointer değişkenini değiştirmeye çalışıyoruz.
    2. *str = 'a';: GEÇERSİZ . Bu işaretçinin işaret ettiği verileri de değiştirmeye çalışıyoruz ki bu da sabittir.

Benim durumumda, görsel olarak eskisine daha yakın göründüğü için değil constexpr char* strgibi davranmayı bekliyordum .const char* strchar* const str

Ayrıca, için oluşturulan uyarı constexpr char* str = "some string"biraz farklıdır char* str = "some string".

  1. Derleyici uyarısı constexpr char* str = "some string":ISO C++11 does not allow conversion from string literal to 'char *const'
  2. İçin Derleyici uyarı char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.

İpucu

Sen kullanabilirsiniz C anlamsız ↔ İngilizce dönüştürücü dönüştürme için Ckolayca anlaşılabilir İngilizce açıklamalara bildirimleri ve tersi de geçerlidir. Bu Ctek bir araçtır ve bu nedenle münhasır olan şeyleri (constexpr gibi) desteklemeyecektir C++.


0

Aynı problemi de aldım. Ve basit yaptığım sadece char * yerine const char * eklemektir. Ve sorun çözüldü. Diğerlerinin yukarıda belirttiği gibi uyumlu bir hatadır. C, karakter dizilerini karakter dizileri olarak ele alırken, C ++ karakter dizilerini karakter dizileri olarak ele alır.


0

Ne için değer, ben bu basit sarmalayıcı sınıf C ++ dizeleri dönüştürmek için yararlı bulmak char *:

class StringWrapper {
    std::vector<char> vec;
public:
    StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
    }

    char *getChars() {
        return &vec[0];
    }
};

-1

Aşağıdaki çözümü gösterir, dizenizi sabit bir char dizisine değişken bir işaretçiye atayın (dize, sabit char dizisine sabit bir işaretçidir - artı uzunluk bilgisi):

#include <iostream>

void Swap(const char * & left, const char * & right) {
    const char *const temp = left;
    left = right;
    right = temp;
}

int main() {
    const char * x = "Hello"; // These works because you are making a variable
    const char * y = "World"; // pointer to a constant string
    std::cout << "x = " << x << ", y = " << y << '\n';
    Swap(x, y);
    std::cout << "x = " << x << ", y = " << y << '\n';
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.