GCC'de `` dize sabitinden 'char *' 'uyarılarından kaldırılan dönüşümden nasıl kurtulurum?


409

Bu yüzden son derece büyük bir kod tabanı üzerinde çalışıyorum ve son zamanlarda şimdi bu uyarıyı tetikleyen gcc 4.3'e yükseltildim:

uyarı: dize sabitinden 'char *' değerine kullanımdan kaldırıldı

Açıkçası, bunu düzeltmenin doğru yolu her bildirimi bulmaktır.

char *s = "constant string";

veya işlev çağrısı aşağıdaki gibi:

void foo(char *s);
foo("constant string");

ve onlara const charişaretçi olun. Ancak, bu, en az 564 dosyaya dokunmak anlamına gelir, bu da bu noktada gerçekleştirmek istediğim bir görev değildir. Şu anda sorun şu ki birlikte çalışıyorum -werror, bu yüzden bu uyarıları bastırmanın bir yolunu bulmalıyım. Bunu nasıl yapabilirim?


554 çizginin yerine geçmeye geldiğinizde sed iyi bir arkadaştır. Yine de yedeklediğinizden emin olun.
Matt

2
Hata mesajlarının nasıl bastırılacağı ve doğru değişikliklerin ne olması gerektiği konusundaki tartışmalara baktım. Bu konuda hiçbir fikrim yok. Ancak, Matt'in doğru yolda olduğunu düşünüyorum. Neyi neyle değiştirmek istediğinizi tanımlayın. Sadece doğru düzenli ifadelere ihtiyacınız var. Bir kopyada değişiklikleri yapın. Orijinal ile karşılaştırmak için "diff" kullanın. Sed kullanarak değişiklik yapmak hızlı, kolay ve ücretsizdir ve fark hızlı, kolay ve ücretsizdir. Deneyin ve kaç değişiklik incelemeniz gerektiğini görün. Neyi neyle değiştirmek istediğinizi yayınlayın ve kullanıcıların normal ifadeleri değiştirmelerini önerin.
Thomas Hedden

Tüm tartışma, bunun neden gcc uyarısına göre düzeltilmesi gereken bir sorun olduğu noktasını kaçırıyor . Nedeni David Schwartz'ın cevabı stackoverflow.com/questions/56522654/… .
andig

Yanıtlar:


227

-Wno-write-stringsGcc'ye geçmenin bu uyarıyı bastıracağına inanıyorum .


6
Pragg kullanarak temel dosya başına devre dışı bırakılabilir.
Priyank Bolia

18
@PriyankBolia bdonlan, Rob Walker'ın kullanabileceği cevabı hakkında yorum yaptı #pragma GCC diagnostic ignored "-Wwrite-strings".
MasterMastic

9
API'yı kontrol ederseniz, bu durumda @ John'un aşağıdaki cevabı, const char * kabul etmek için imzayı değiştirmekle ilgili daha doğrudur.
jcwenger

215
BU KORKUNÇ KÖTÜ UYGULAMA ve tüm bu oyları aldığı için üzgünüm. Uyarılar yok sayılır, böylece yok sayılırsınız. Uyarılar var "dostum, yanlış olabilecek bir şey yapıyorsun, dikkatli ol" diyorlar ve sadece "sus, ne yaptığımı biliyorum" gibi cevap vermek istediğinde onları bastırmalısın. bebek programcılarında durum böyle değil.
Kuantum Fizikçisi

9
Katılıyorum, uyarıdan kurtulmamalı ve bunun yerine John tarafından sağlanan çözümü kullanmamalısınız. Çok kötü bu kabul edilen cevap!
Jérôme

563

Herhangi fonksiyonlar İçine dize hazır geçmesi "I am a string literal"kullanmalıdır char const *yerine türü olarak char*.

Bir şeyi düzeltirseniz, düzeltin.

Açıklama:

Değiştirilecek dizeleri başlatmak için dize değişmezlerini kullanamazsınız, çünkü bunlar türdedir const char*. Daha sonra bunları değiştirmek için constness uzakta Casting olduğunu tanımsız davranış size kopyalamak zorunda, const char*dizeleri chartarafından chardinamik olarak tahsis içine char*bunları değiştirmek için dizeleri.

Misal:

#include <iostream>

void print(char* ch);

void print(const char* ch) {
    std::cout<<ch;
}

int main() {
    print("Hello");
    return 0;
}

25
Bu doğru olsa da, her zaman doğru şekilde char */ kullanamayan 3. taraf API'leri üzerinde kontrolünüz yoktur const char *, bu durumda normalde yayınlarım.
ideasman42 02

15
@ppumkin Ne yazık ki, birçok C standart kitaplık dizesi işlevi char*değiştirilmeyecek dizeler için bile bağımsız değişkenler alıyor . Bir parametreyi a olarak alıp char const*standart bir fonksiyona geçirirseniz, bunu char*vuracaksınız. Kitaplık işlevi dizeyi değiştirmeyecekse const,.
John

Her zaman mümkün olmaması, bu uyarının çoğu zaman ortak üretim kodunda görünmesi için tercih edilen seçenek olmadığı anlamına gelmez.
LovesTha

1
Şimdi dize değişmezlerinin çözümünü ve işlevselliğini tam olarak anlıyorum. Ama belki başkaları yapmaz, bu yüzden bir açıklama ihtiyacını '
tutuyorum

1
Çözümünüzü nasıl uygulayacağınızı anlamıyorum :(
desmond13

69

Benzer bir sorunum vardı, bunu şu şekilde çözdüm:

#include <string.h>

extern void foo(char* m);

int main() {
    // warning: deprecated conversion from string constant to ‘char*’
    //foo("Hello");

    // no more warning
    char msg[] = "Hello";
    foo(msg);
}

Bunu çözmenin uygun bir yolu var mı? Kabul etmek fooiçin adapte etmek için erişimim yok const char*, ancak bu daha iyi bir çözüm olacaktır (çünkü foodeğişmez m).


8
@elcuco, ne önerirsiniz? Foo'yu düzenleyemedim ve uyarının bastırılmasını gerektirmeyen bir çözüm bulmaya çalıştım. Benim durumumda, ikincisi daha çok bir egzersiz meselesiydi, ancak orijinal poster için önemli görünüyordu. Anlayabildiğim kadarıyla, cevabım hem benim hem de OP'nin koşullarını aynı anda çözecek olan tek şey, bu yüzden birine değerli bir cevap olabilir. Çözümümün yeterince iyi olmadığını düşünüyorsanız, lütfen bir alternatif verebilir misiniz? (Bu, foo düzenlemeyi veya uyarıyı yok
saymayı içermez

foo'nun düzgün kodlandığını varsayarsak (maalesef 'Josh Matthews' kodunun söz konusu olduğu gibi görünmüyor) bu en iyi çözümdür. çünkü fonksiyon aslında 'msg' dizesini sürekli bir dize geçirerek değiştirirse, kodu kıracaktır, değil mi? ancak yine de bu soruya cevap vermiyor gibi görünüyor, çünkü hatalar zaten eski kodda yeni değil, bu yüzden yine de eski kodu değiştirmeniz gerekiyor.
João Portela

Benim de benim yaklaşımım bu. Ve birileri durumlar için bu arama yapıyorsa, char **içinde PyArg_ParseTupleAndKeywordsböyle bir şey yapın:static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};
dashesy

@elcuco: C ++ statik dizilerinin nasıl çalıştığından emin değilim. Bu sadece işaretçi değil, herhangi bir veriyi gerçekten kopyalayacak mı?
Alexander Malakhov

Her ne kadar bu yaklaşım körü körüne uygulanıyorsa, IMO'nun yarardan çok zarar verme olasılığı yüksektir. Bunu körü körüne uygulamak, kolayca sarkan işaretlere yol açabilir. Ayrıca, kodu anlamsız dizgi kopyalarıyla şişirir.
plugwash


30

Etkin bir kod tabanı ise, kod tabanını yükseltmek isteyebilirsiniz. Tabii ki, değişiklikleri manuel olarak yapmak mümkün değildir, ancak bu sorunun bir kez ve herkes için tek bir sedkomutla çözülebileceğine inanıyorum . Yine de denemedim, bu yüzden aşağıdakileri bir tuz tanesi ile alın.

find . -exec sed -E -i .backup -n \
    -e 's/char\s*\*\s*(\w+)\s*= "/char const* \1 = "/g' {} \;

Bu, tüm yerleri bulamayabilir (işlev çağrılarını dikkate almasa bile), sorunu hafifletir ve kalan birkaç değişikliği manuel olarak gerçekleştirmeyi mümkün kılar.


7
Bu sadece uyarı uyarıları çözer ve zaten sed fu için +1 çağrıları değil: p
João Portela

25

Derleyici anahtarını kullanamıyorum. Bu yüzden bunu çevirdim:

char *setf = tigetstr("setf");

buna:

char *setf = tigetstr((char *)"setf");

1
+1 - uygulamaların değerini değiştiremezsiniz, yalnızca değerdir. bu gerçek sorunu çözdü. diğer sadece derleyici ile bazı sorunlar üzerinde çalışmak.
elcuco

1
Gerçekten sinir bozucu olan şey, tigetstr () 'in (char *) ile değil (const char *) ile prototiplenmesi gerektiğidir
vy32

2
Bunu yaptığımda "uyarı: 'const char *' türünden 'char *' yazmak için cast 'constness uzağa" alıyorum. Tüm uyarılardan kurtulmak için bir const_cast kullanmak zorunda kaldım: const_cast <char *> ("setf")
CrouZ

2
Ben const döküm bu sayfada kabul edilebilir ilk çözüm olduğunu düşünüyorum (API değişiklik hariç).
rwst

25

İşte bir dosyada satır içi nasıl yapılacağından Makefile'nizi değiştirmeniz gerekmez.

// gets rid of annoying "deprecated conversion from string constant blah blah" warning
#pragma GCC diagnostic ignored "-Wwrite-strings"

Daha sonra yapabilirsiniz ...

#pragma GCC diagnostic pop

25

değiştirmek

char *str = "hello";

ile

char *str = (char*)"hello";

veya işlevde arıyorsanız:

foo("hello");

bunu ile değiştir

foo((char*) "hello");

15

Onun yerine:

void foo(char *s);
foo("constant string");

Bu çalışıyor:

void foo(const char s[]);
foo("constant string");

Bunu yapmanın doğru yolu, çünkü sabit olmayan bir dize zaten bekleyen bir işleve (sabit) bir dize geçirmemelisiniz!
jfla

15

C ++ ' const_castda aşağıdaki gibi kullanın

char* str = const_cast<char*>("Test string");

7

Test stringconst dizesidir. Böylece şu şekilde çözebilirsiniz:

char str[] = "Test string";

veya:

const char* str = "Test string";
printf(str);

4

Neden sadece dökümü kullanmıyorsunuz?

(char*) "test"

2

Sabit dizgiden karakter işaretçisine yazım vb.

char *s = (char *) "constant string";

1

C ++ 'da değiştirin:

char *str = "hello";

ile:

std::string str ("hello");

Ve karşılaştırmak isterseniz:

str.compare("HALLO");

1

Çözümünüzü nasıl uygulayacağınızı anlamıyorum :( - kalmanIsAGameChanger

Arduino Sketch ile çalışırken uyarılarıma neden olan bir fonksiyonum vardı.

Orijinal işlev: char StrContains (char * str, char * sfind)

Uyarıları durdurmak için ekledim const char önünde * str ve karakter * sfind.

Değiştirildi: char StrContains (const char * str, const char * sfind).

Tüm uyarılar ortadan kalktı.


Uyarının söylediği gibi bu doğru cevaptır: "uyarı: dize sabitinden 'char *' değerine kullanımdan kaldırıldı".
Norbert Boros

0

bu duruma bakın:

typedef struct tagPyTypeObject
{
    PyObject_HEAD;
    char *name;
    PrintFun print;
    AddFun add;
    HashFun hash;
} PyTypeObject;

PyTypeObject PyDict_Type=
{
    PyObject_HEAD_INIT(&PyType_Type),
    "dict",
    dict_print,
    0,
    0
};

ad alanını izlemek, gcc uyarı olmadan derlemek, ancak g ++ bu, neden bilmiyorum.


gcc, dosyayı C kaynak dosyası olarak kabul eder, g ++, c ++ kaynak dosyası olarak davranır, -x ile geçersiz kılmadıkça ?? seçeneği. Yani farklı bir dilde, c ve c ++ neyin uyarılması gerektiği konusunda ince farklar var.
zhaorufei

0

Ayrıca arayarak bir dize sabitinden yazılabilir bir dize oluşturabilirsiniz strdup().

Örneğin, bu kod bir uyarı oluşturur:

putenv("DEBUG=1");

Ancak, aşağıdaki kod yapmaz (dizeden geçirmeden önce dizenin bir kopyasını oluşturur putenv):

putenv(strdup("DEBUG=1"));

Bu durumda (ve belki de diğerlerinin çoğunda) uyarıyı kapatmak kötü bir fikirdir - bir nedenden dolayı oradadır. Diğer alternatif (tüm dizeleri varsayılan olarak yazılabilir yapma) potansiyel olarak verimsizdir.

Derleyicinin size söylediklerini dinleyin!


6
Ayrıca yazılabilir dize için ayrılan belleği de sızdırıyor.
RBerteig

1
Evet öyle - bilerek. Yukarıdaki gibi bir kerelik kodla (örneğin başlatma) sorun değil. Veya belleği kendiniz yönetebilir ve işiniz bittiğinde serbest bırakabilirsiniz.
BillAtHRST

1
Belirli bir durum putenv()doludur - iyi bir örnek seçim değildir (en azından, putenv()bu cevapta olduğundan daha fazla ne olduğunu tartışmadan ). Bu tamamen ayrı bir tartışma. ( putenv()POSIX'in tanımlanmasından önceki eski uygulamalara bağlı olarak , davranışı için POSIX belirtiminin sorunlu olduğunu unutmayın .) IIRC, GNU C Kütüphanesinin son zamanlarda (bu binyıl) sürümde putenv()davranış değişikliği ile ilgili bir hata olduğunu , ve değişti.)
Jonathan Leffler

0

sadece g ++ için -w seçeneğini kullanın

misal:

g ++ -w -o simple.o simple.cpp -lpthread

Bunun kullanımdan kaldırılmayı önlemediğini, bunun yerine terminalde uyarı mesajı gösterilmesini engellediğini unutmayın.

Artık gerçekten kullanımdan kaçınmak istiyorsanız const anahtar sözcüğünü şu şekilde kullanın:

const char* s="constant string";  

0

Neden kullanımdan -Wno-deprecatedkaldırılmış uyarı mesajlarını yok saymak için bu seçeneği kullanmıyorsunuz ?


0

Şu anda sorun şu ki -Werror ile çalışıyorum

Bu senin gerçek sorunun, IMO. (Char *) 'dan (const char *)' a geçmenin bazı otomatik yollarını deneyebilirsiniz, ancak onlara sadece çalışma değil para koyarım. İşin en azından bir kısmı için bir insanın olması gerekir. Kısa vadede, uyarıyı göz ardı edin (ancak IMO bunu açık bırakın, yoksa sabitlenmeyecektir) ve -Werror'u kaldırın.


9
Bunun sebebi, insanların -Werror kullanmamak uyarıları öyle mi kullanmak do tamir et. Aksi takdirde asla sabitlenmezler.
Zan Lynx

2
İnsanların -Ferror'u kullanmasının nedeni, sadece oyuncak projelerinde çalıştıkları veya mazoşist olduklarıdır. 100k + LOC'niz olduğunda GCC güncellemesi nedeniyle kodunuzun derlenememesi gerçek bir sorundur. Dito. can sıkıcı uyarılardan kurtulmak için yapıya "-Wno-write-string" gibi önemsiz ekleyen biri (bu yazıdaki en yüksek puanlı yorum gibi).
James Antill

2
bu konuda açık bir anlaşmazlık var, örneğin programcı.97things.oreilly.com
wiki/index.php/…

3
@James: İlginç bir noktaya değindin, ama daha iyi bir yol olmalı. Uyarıları hemen düzeltmemek anlamsız görünüyor - yeni kodun tüm eski uyarıları kaldırmamanız durumunda yeni bir uyarı başlattığını nasıl anlarsınız? Deneyimlerime göre, bu sadece insanların görmezden gelmemesi gereken uyarıları görmezden gelmesine yol açar.
nobar

2
@James: Oyuncak projemiz 1.5 + M LOC (çok dilli). Nobar'ın dediği gibi, -Perror olmaması gereken uyarıları göz ardı etmekten kaçınır ve evet, derleyicinin her yeni sürümü yükseldiğinde, hepsini tekrar kontrol etmeliyiz. -Wno-write-strings sadece bir dosyada dosya olarak python sarmalayıcıları için Boost kullanılırken kullanılır, çünkü Boost'u yeniden yazmayacağız (ve şu anda 2017'de artık Boost'u değil C ++ 11 / Cython). Göz ardı edilen her uyarı, artık kod tarafından önlenip önlenemeyeceğini veya henüz mümkün olup olmadığını görmek için kalite kontrolü tarafından periyodik olarak gözden geçirilmelidir.
msn

0

Yardımlarınız için teşekkürler. Buradan seçip bu çözüm geliyor. Bu temiz derler. Kodu henüz test etmedim. Belki yarın...

const char * timeServer[] = { "pool.ntp.org" }; // 0 - Worldwide 
#define WHICH_NTP            0 // Which NTP server name to use.
...
sendNTPpacket(const_cast<char*>(timeServer[WHICH_NTP])); // send an NTP packet to a server
...
void sendNTPpacket(char* address) { code }

Biliyorum, timeServer dizisinde sadece 1 öğe var. Ama daha fazlası da olabilirdi. Geri kalanı şimdilik bellek tasarrufu yapmak için yorumlandı.


-1
PyTypeObject PyDict_Type=
{ ...

PyTypeObject PyDict_Type=
{
  PyObject_HEAD_INIT(&PyType_Type),
                     "dict",
                     dict_print,
                     0,
                     0
}; 

ad alanını izlemek, gcc uyarı olmadan derlemek, ancak g ++ bu, neden bilmiyorum.

içinde gcc (Compiling C) , -Wno-write-stringleri varsayılan olarak etkindir.

içinde g++ (Compiling C++) -Wwrite-dizeleri varsayılan olarak etkindir

Bu yüzden farklı bir davranış var. Bizim için makrolar Boost_pythonbu tür uyarılar üretir. Bu yüzden -Wno-write-stringsher zaman kullandığımız için C ++ derlerken kullanıyoruz-Werror


-1

constSorunu çözecek bir dize olarak bildirin :

char const*s = "constant string";
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.