Bagaimana cara menyingkirkan `konversi yang ditinggalkan dari string konstan ke peringatan 'char *'` di GCC?


409

Jadi saya sedang mengerjakan basis kode yang sangat besar, dan baru-baru ini ditingkatkan menjadi gcc 4.3, yang sekarang memicu peringatan ini:

peringatan: konversi yang tidak digunakan lagi dari string konstan ke 'char *'

Jelas, cara yang benar untuk memperbaikinya adalah dengan menemukan setiap deklarasi suka

char *s = "constant string";

atau panggilan fungsi seperti:

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

dan membuat mereka const charpetunjuk. Namun, itu berarti menyentuh 564 file, minimum, yang bukan tugas yang ingin saya lakukan pada saat ini. Masalahnya sekarang adalah saya sedang berlari -werror, jadi saya perlu cara untuk meredam peringatan ini. Bagaimana saya bisa melakukan itu?


Ketika Anda datang untuk mengatasi mengganti 554 baris, sed adalah teman yang baik. Pastikan Anda membuat cadangan terlebih dahulu.
Matt

2
Saya melihat diskusi tentang bagaimana menekan pesan kesalahan dan apa yang harus diganti. Saya tidak punya pendapat tentang itu. Namun, saya pikir Matt ada di jalur yang benar. Tentukan apa yang ingin Anda ganti dengan apa. Anda hanya perlu persamaan reguler yang tepat. Buat perubahan dalam salinan. Gunakan "diff" untuk membandingkannya dengan yang asli. Membuat perubahan menggunakan sed cepat, mudah dan gratis, dan diff juga cepat, mudah dan gratis. Cobalah dan lihat berapa banyak perubahan yang harus Anda tinjau. Poskan apa yang ingin Anda ganti dengan apa, dan biarkan pengguna menyarankan penggantian regex.
Thomas Hedden

Seluruh diskusi tidak ada gunanya mengapa ini merupakan masalah yang perlu diperbaiki sama sekali menurut peringatan gcc. Alasannya ada di jawaban David Schwartz ' stackoverflow.com/questions/56522654/… .
andig

Jawaban:


227

Saya percaya melewatinya -Wno-write-stringske gcc akan menekan peringatan ini.


6
Apakah itu dapat dinonaktifkan pada per file dasar menggunakan pragma.
Priyank Bolia

18
@PriyankBolia bdonlan mengomentari jawaban Rob Walker yang dapat digunakan #pragma GCC diagnostic ignored "-Wwrite-strings".
MasterMastic

9
Kecuali jika Anda mengontrol API, dalam hal ini jawaban @ John di bawah ini, tentang mengubah tanda tangan untuk menerima const char *, lebih tepat.
jcwenger

215
INI PRAKTEK YANG MENGERIKAN BURUK, dan saya sedih mendapat semua suara itu. Peringatan tidak ada sehingga Anda mengabaikannya. Peringatan ada di sana memberi tahu Anda "bung, Anda melakukan sesuatu yang bisa salah, hati-hati", dan Anda hanya harus menekan mereka ketika Anda ingin menjawab seperti "diam, aku tahu apa yang saya lakukan", yang kemungkinan besar tidak halnya dengan programmer bayi.
Fisikawan Quantum

9
Saya setuju, Anda tidak harus menyingkirkan peringatan dan bukannya menggunakan solusi yang disediakan oleh John. Sayang sekali jawaban yang ini diterima!
Jérôme

564

Fungsi apa pun yang Anda "I am a string literal"gunakan string literal harus digunakan char const *sebagai jenis alih-alih char*.

Jika Anda akan memperbaiki sesuatu, perbaiki dengan benar.

Penjelasan:

Anda tidak dapat menggunakan string literal untuk menginisialisasi string yang akan dimodifikasi, karena mereka bertipe const char*. Casting pergi constness untuk kemudian memodifikasi mereka adalah perilaku undefined , sehingga Anda harus menyalin Anda const char*string chardengan charmenjadi dinamis dialokasikan char*string dalam rangka untuk mengubah mereka.

Contoh:

#include <iostream>

void print(char* ch);

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

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

25
Meskipun ini benar, Anda tidak selalu memiliki kontrol atas API pihak ke-3 yang mungkin tidak menggunakan char */ const char *, jadi dalam hal ini saya biasanya menggunakan.
ideasman42

15
@ ppumkin Sayangnya, banyak fungsi string library C standar mengambil argumen char*bahkan untuk string yang tidak akan diubah. Jika Anda mengambil parameter sebagai char const*dan meneruskannya ke fungsi standar, char*Anda akan menemukan itu. Jika fungsi perpustakaan tidak akan memanipulasi string, Anda dapat membuang const.
John

Hanya karena itu tidak selalu mungkin, bukan berarti itu bukan pilihan yang disukai untuk banyak kali peringatan ini muncul dalam kode produksi umum.
LovesTha

1
Saya sekarang sepenuhnya memahami solusi, dan fungsi string literal. Tapi mungkin yang lain tidak, jadi saya 'memegang' kebutuhan akan penjelasan
NicoBerrogorry

1
Saya tidak mengerti bagaimana cara menerapkan solusi Anda :(
desmond13

69

Saya memiliki masalah yang sama, saya menyelesaikannya seperti ini:

#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);
}

Apakah ini cara yang tepat untuk menyelesaikan ini? Saya tidak memiliki akses untuk foomengadaptasikannya untuk menerima const char*, meskipun itu akan menjadi solusi yang lebih baik (karena footidak berubah m).


8
@elcuco, apa yang akan Anda usulkan? Saya tidak dapat mengedit foo, dan mencoba menemukan solusi yang tidak memerlukan penindasan terhadap peringatan tersebut. Dalam kasus saya yang terakhir ini lebih merupakan masalah olahraga, tetapi untuk poster aslinya sepertinya penting. Sejauh yang saya tahu, jawaban saya adalah satu-satunya yang akan menyelesaikan kondisi saya dan OP pada saat yang sama sehingga itu bisa menjadi jawaban yang berharga bagi seseorang. Jika menurut Anda solusi saya tidak cukup baik, bisakah Anda memberikan alternatif? (Itu tidak termasuk mengedit foo atau mengabaikan peringatan.)
BlackShift

jika kita berasumsi bahwa foo dikodekan dengan benar (yang sayangnya sepertinya tidak berlaku untuk kode 'Josh Matthews' yang dibicarakan) ini adalah solusi terbaik. itu karena jika fungsi harus benar-benar mengubah string 'msg' melewatinya string konstan akan memecah kode, kan? tapi bagaimanapun ini sepertinya tidak menjawab pertanyaan karena kesalahan sudah ada di kode lama bukan di yang baru, jadi dia perlu mengubah kode lama pula.
João Portela

Itulah pendekatan yang saya ambil juga. Dan jika seseorang mencari ini untuk kasus char **di PyArg_ParseTupleAndKeywordssaya melakukan sesuatu seperti ini:static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};
dashesy

@elcuco: Saya tidak yakin bagaimana C ++ array statis bekerja. Apakah ini benar-benar menyalin data apa pun, dan bukan hanya penunjuk?
Alexander Malakhov

Meskipun pendekatan ini mungkin memiliki manfaat dalam beberapa kasus menerapkannya secara membabi buta adalah IMO cenderung melakukan lebih banyak ruginya daripada kebaikan. Menerapkan ini secara membabi buta dapat dengan mudah menyebabkan pointer menggantung. Ini juga akan mengasapi kode dengan salinan string yang tidak berguna.
plugwash


30

Jika basis kode aktif, Anda mungkin masih ingin meningkatkan basis kode. Tentu saja, melakukan perubahan secara manual tidak layak tetapi saya percaya bahwa masalah ini dapat diselesaikan sekali dan untuk semua dengan satu sedperintah tunggal . Saya belum mencobanya, jadi ambil yang berikut dengan sebutir garam.

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

Ini mungkin tidak menemukan semua tempat (bahkan tidak mempertimbangkan panggilan fungsi) tetapi itu akan mengurangi masalah dan memungkinkan untuk melakukan beberapa perubahan yang tersisa secara manual.


7
itu hanya memecahkan peringatan deklarasi dan tidak berfungsi memanggil +1 untuk sed fu pula: p
João Portela

25

Saya tidak bisa menggunakan saklar kompiler. Jadi saya telah mengubah ini:

char *setf = tigetstr("setf");

untuk ini:

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

1
+1 - Anda tidak dapat mengubah nilai aplikasi, hanya nilai saja. ini terbukti memperbaiki masalah sebenarnya. lainnya hanya mengatasi beberapa masalah dengan kompiler.
elcuco

1
Hal yang benar-benar menjengkelkan adalah bahwa tigetstr () harus prototyped dengan (const char *), bukan (char *)
vy32

2
Ketika saya melakukan ini saya mendapatkan "peringatan: gulir dari tipe 'const char *' untuk mengetik 'char *' membuang constness" sebagai gantinya. Saya harus menggunakan const_cast untuk menghilangkan semua peringatan: const_cast <char *> ("setf")
CrouZ

2
Saya pikir cast const adalah solusi pertama yang dapat diterima di halaman ini (kecuali perubahan API).
pertama

25

Berikut ini cara melakukannya dalam file, jadi Anda tidak perlu memodifikasi Makefile Anda.

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

Anda kemudian dapat ...

#pragma GCC diagnostic pop

25

Menggantikan

char *str = "hello";

dengan

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

atau jika Anda memanggil fungsi:

foo("hello");

ganti ini dengan

foo((char*) "hello");

15

Dari pada:

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

Ini bekerja:

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

Ini adalah cara yang benar untuk melakukannya karena Anda seharusnya tidak meneruskan string (konstan) ke fungsi yang mengharapkan string tidak konstan!
jfla

15

Di C ++, gunakan const_castseperti di bawah ini

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

7

Test stringadalah string const. Jadi Anda bisa menyelesaikannya seperti ini:

char str[] = "Test string";

atau:

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

4

Mengapa tidak menggunakan tipe casting saja?

(char*) "test"

2

Apakah typecasting dari string konstan ke pointer char yaitu

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

1

Di C ++, Ganti:

char *str = "hello";

dengan:

std::string str ("hello");

Dan jika Anda ingin membandingkannya:

str.compare("HALLO");

1

Saya tidak mengerti bagaimana cara menerapkan solusi Anda :( - kalmanIsAGameChanger

Bekerja dengan Arduino Sketch, saya memiliki fungsi yang menyebabkan peringatan saya.

Fungsi asli: char StrContains (char * str, char * sfind)

Untuk menghentikan peringatan, saya menambahkan const di depan karakter * dan karakter *.

Dimodifikasi: char StrContains (const char * str, const char * sfind).

Semua peringatan hilang.


Ini adalah jawaban yang benar sesuai dengan peringatan yang mengatakan: "peringatan: konversi yang ditinggalkan dari string konstan ke 'char *'".
Norbert Boros

0

lihat situasi ini:

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
};

perhatikan bidang nama, di gcc kompilasi tanpa peringatan, tetapi di g ++ itu akan, saya tidak tahu mengapa.


gcc menyiratkan memperlakukan file sebagai file sumber C, g ++ memperlakukannya sebagai file sumber c ++, kecuali ditimpa oleh -x ?? pilihan. Jadi bahasa yang berbeda, c dan c ++ memiliki perbedaan halus tentang apa yang seharusnya menjadi peringatan.
zhaorufei

0

Anda juga dapat membuat string yang dapat ditulis dari konstanta string dengan memanggil strdup().

Misalnya, kode ini menghasilkan peringatan:

putenv("DEBUG=1");

Namun, kode berikut ini tidak (itu membuat salinan string di heap sebelum meneruskannya ke putenv):

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

Dalam hal ini (dan mungkin di sebagian besar lainnya) mematikan peringatan adalah ide yang buruk - itu ada karena suatu alasan. Alternatif lain (membuat semua string dapat ditulis secara default) berpotensi tidak efisien.

Dengarkan apa yang dikatakan kompiler!


6
Dan itu juga bocor memori yang dialokasikan untuk string yang dapat ditulisi.
RBerteig

1
Ya itu - itu sengaja. Bukan masalah dengan kode satu kali (misalnya, inisialisasi), seperti di atas. Atau, Anda dapat mengelola memori sendiri dan melepaskannya setelah Anda selesai melakukannya.
BillAtHRST

1
Kasus khusus putenv()penuh - itu bukan pilihan contoh yang baik (setidaknya, tidak tanpa banyak diskusi tentang apa yang putenv()ada daripada dalam jawaban ini). Ini adalah diskusi yang terpisah. (Perhatikan bahwa spesifikasi POSIX untuk perilaku putenv()bermasalah, berdasarkan pada implementasi warisan dari sebelum POSIX didefinisikan.) IIRC, ada bug dalam rilis terbaru (milenium) Perpustakaan GNU C yang berkaitan dengan putenv()perubahan perilaku, dan diubah kembali.)
Jonathan Leffler

0

cukup gunakan opsi -w untuk g ++

contoh:

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

Ingat ini tidak menghindari penghentian melainkan mencegah menampilkan pesan peringatan di terminal.

Sekarang jika Anda benar-benar ingin menghindari penghentian penggunaan kata kunci const seperti ini:

const char* s="constant string";  

0

Mengapa Anda tidak menggunakan -Wno-deprecatedopsi ini untuk mengabaikan pesan peringatan yang sudah usang?


0

Masalahnya sekarang adalah saya menjalankan dengan -Werror

Ini adalah masalah Anda yang sebenarnya, IMO. Anda dapat mencoba beberapa cara otomatis untuk berpindah dari (char *) ke (const char *) tetapi saya akan menggunakan uang untuk itu tidak hanya bekerja. Anda harus melibatkan manusia setidaknya untuk beberapa pekerjaan. Untuk jangka pendek, abaikan saja peringatan (tapi IMO biarkan, atau tidak akan pernah diperbaiki) dan cukup hapus -Werror.


9
Alasan orang menggunakan -Werror adalah agar peringatan jangan diperbaiki. Kalau tidak, mereka tidak akan pernah diperbaiki.
Zan Lynx

2
Alasan orang menggunakan -Werror adalah karena mereka hanya bekerja pada proyek mainan, atau mereka masokis. Memiliki kode Anda gagal dibangun karena pembaruan GCC adalah masalah nyata ketika Anda memiliki 100rb + LOC. Dito. seseorang menambahkan sampah seperti "-Wno-write-string" ke build untuk menghilangkan peringatan yang menjengkelkan (seperti yang disarankan oleh komentar dengan nilai tertinggi dalam posting ini).
James Antill

2
ada perbedaan pendapat yang jelas dalam topik itu, misalnya programmer.97things.oreilly.com/wiki/index.php/…
João Portela

3
@ James: Anda membuat poin yang menarik, tetapi harus ada cara yang lebih baik. Tampaknya tidak ada gunanya untuk tidak segera memperbaiki peringatan - bagaimana Anda mengenali ketika kode baru telah memunculkan peringatan baru ketika Anda belum menghapus semua peringatan lama? Dalam pengalaman saya, itu hanya menyebabkan orang mengabaikan peringatan yang seharusnya tidak mereka abaikan.
Nobar

2
@ James: proyek mainan kami adalah 1,5+ M LOC (multi-bahasa). Seperti kata Nobar, -Werror menghindari mengabaikan peringatan yang seharusnya tidak dan ya, setiap kali versi baru dari kompiler naik, kita harus memeriksa ulang semua. -Wno-write-string hanya digunakan ketika menggunakan Boost untuk pembungkus python dalam file dengan cara file, karena kita tidak akan menulis ulang Boost (dan saat ini, 2017, kami lebih memilih untuk tidak lagi menggunakan Boost tetapi C ++ 11 / cython). Setiap peringatan yang diabaikan harus ditinjau secara berkala dengan pemeriksaan kualitas untuk melihat apakah peringatan tersebut sekarang dapat dihindari dengan kode atau jika belum memungkinkan.
msn

0

Terima kasih atas bantuannya. Memilih dari sana-sini solusi ini. Kompilasi ini bersih. Belum menguji kodenya. Besok mungkin...

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 }

Saya tahu, hanya ada 1 item dalam array timeServer. Tetapi mungkin ada lebih banyak. Sisanya dikomentari untuk saat ini untuk menghemat memori.


-1
PyTypeObject PyDict_Type=
{ ...

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

perhatikan bidang nama, di gcc kompilasi tanpa peringatan, tetapi di g ++ itu akan, saya tidak tahu mengapa.

di gcc (Compiling C), -Wno-write-string aktif secara default.

di g++ (Compiling C++)-Wwrite-string aktif secara default

Inilah sebabnya mengapa ada perilaku yang berbeda. Bagi kami menggunakan makro Boost_pythonmenghasilkan peringatan seperti itu. Jadi kami menggunakan -Wno-write-stringsketika mengkompilasi C ++ karena kami selalu menggunakan-Werror


-1

Nyatakan string sebagai constkehendak memecahkan masalah:

char const*s = "constant string";
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.