C ++ konversi usang dari string konstan ke 'char *'

154

Saya memiliki kelas dengan private char str[256];

dan untuk itu saya memiliki konstruktor eksplisit:

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

Saya menyebutnya sebagai:

myClass obj("example");

Ketika saya mengkompilasi ini saya mendapatkan peringatan berikut:

konversi usang dari konstanta string ke 'char *'

Mengapa ini terjadi?

mkamthan
sumber
1
Anda harus menggunakan strncpy(str, func, 255)alih-alih strcpy(str, func)untuk salinan yang lebih aman. Dan jangan lupa untuk menambahkan '\ 0' di akhir string karena strncpy tidak menambahkannya.
Patrice Bernassola
2
Lebih aman untuk mengatakan "strncpy (str, func, sizeof (str)); str [sizeof (str) - 1] = '\ 0';"
Warren Young
3
Saya tidak berpikir di atas memberikan peringatan yang Anda kutip, meskipun saya yakin kode yang cukup mirip. Untuk mendapatkan jawaban yang bermakna, Anda harus memposting contoh kompilasi minimal yang menghasilkan peringatan.
sbi
3
@ Patrice, Warren: jangan gunakan strncpy, ini bukan versi yang lebih aman dari strcpy. Gunakan (atau implementasikan kembali) strcpy_s.
Steve Jessop
Saya mendapat masalah, hanya menunjukkan masalah ini untuk build -X86 dan bukan untuk solaris normal atau ARM (target) build jadi saya mengabaikan ini. Tidak dapat menemukan perbaikan karena tidak menunjukkan peringatan secara normal untuk kode sampel saya juga. Terima kasih semua!
mkamthan

Jawaban:

144

Ini adalah pesan kesalahan yang Anda lihat setiap kali Anda memiliki situasi seperti berikut:

char* pointer_to_nonconst = "string literal";

Mengapa? Nah, C dan C ++ berbeda dalam jenis string literal. Dalam C jenisnya adalah array char dan dalam C ++ itu adalah array konstan char. Dalam kasus apa pun, Anda tidak diperbolehkan untuk mengubah karakter string literal, sehingga const di C ++ sebenarnya bukan batasan tetapi lebih merupakan jenis keamanan. Konversi dari const char*ke char*umumnya tidak mungkin dilakukan tanpa pemeran eksplisit untuk alasan keamanan. Tetapi untuk kompatibilitas mundur dengan C bahasa C ++ masih memungkinkan menetapkan string literal ke a char*dan memberi Anda peringatan tentang konversi ini menjadi usang.

Jadi, di suatu tempat Anda kehilangan satu atau lebih constdalam program Anda untuk kebenaran const. Tetapi kode yang Anda tunjukkan kepada kami bukanlah masalah karena tidak melakukan konversi yang sudah usang ini. Peringatan itu pasti datang dari tempat lain.

sellibitze
sumber
17
Sangat disayangkan mengingat pandangan dan suara pada pertanyaan ini bahwa OP tidak pernah memberikan kode yang benar-benar menunjukkan masalah.
Shafik Yaghmour
1
Anda dapat mereproduksi masalah dengan kode OP dengan menghapusnya constdari MyClasskonstruktor ... lalu Anda dapat memperbaikinya dengan menambahkan constkembali.
Theodore Murdock
145

Peringatan:

konversi usang dari konstanta string ke 'char *'

diberikan karena Anda melakukan sesuatu (bukan dalam kode yang Anda posting) sesuatu seperti:

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

Masalahnya adalah bahwa Anda mencoba untuk mengubah string literal (dengan tipe const char[]) menjadi char*.

Anda dapat mengkonversi const char[]ke const char*karena array meluruh ke pointer, tetapi apa yang Anda lakukan adalah membuat sebuah konstanta bisa berubah.

Konversi ini mungkin diizinkan untuk kompatibilitas C dan hanya memberi Anda peringatan yang disebutkan.

fnieto - Fernando Nieto
sumber
96

Sebagai jawaban tidak. 2 oleh fnieto - Fernando Nieto dengan jelas dan benar menjelaskan bahwa peringatan ini diberikan karena di suatu tempat dalam kode Anda yang Anda lakukan (bukan dalam kode yang Anda posting) sesuatu seperti:

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

Namun, jika Anda juga ingin menjaga kode Anda bebas dari peringatan maka cukup lakukan perubahan pada kode Anda:

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

Artinya, cukup masukkan stringkonstanta ke (char *).

sactiw
sumber
17
Atau, buat fungsi: void foo (const char * str)
Caprooja
3
@Caprooja Ya mendeklarasikan param sebagai 'pointer ke konstanta' juga akan berfungsi dalam kasus ini. Tetapi dengan perubahan ini, pengguna tidak dapat lagi mengubah / menetapkan kembali nilai yang disimpan di alamat menggunakan pointer 'str' yang mungkin dilakukan pengguna di bagian implementasi. Jadi itu adalah sesuatu yang mungkin ingin Anda waspadai.
sactiw
1
@sactiw Apakah ada alasan untuk tetap void foo(char* str)seperti ini? Saya pikir kita tidak bisa modity strdalam cara apa foopun, bahkan parameter ditulis sebagai non-const.
kgf3JfUtW
37

Ada 3 solusi:

Solusi 1:

const char *x = "foo bar";

Solusi 2:

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

Solusi 3:

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

Array juga dapat digunakan sebagai ganti pointer karena array sudah menjadi pointer konstan.

anilbey
sumber
7
Untuk Solusi 3, ada strdup. Tidak seperti kode Anda, itu akan mengalokasikan ruang untuk karakter NUL terminating, dan tidak membanjiri alokasi.
Ben Voigt
2
Solusi 2 harus dihindari.
Lightness Races in Orbit
Sebenarnya solusi 2 dapat berupa: char * x = static_cast <char *> ("foo bar") di C ++.
Kehe CAI
3
Anil akankah Anda mengintegrasikan komentar ke dalam jawaban Anda? Solusi 3 masih sangat salah.
Lightness Races in Orbit
@LightnessRacesinOrbit Bisakah Anda memberikan jawaban? Saya tidak mengerti mengapa Anda mengatakan Solusi 2 dan 3 harus dihindari dan salah berbahaya.
Gladclef
4

Sebenarnya string konstanta literal bukanlah const char * atau char * tetapi char []. Cukup aneh tapi ditulis dalam spesifikasi c ++; Jika Anda memodifikasinya perilaku tidak terdefinisi karena kompiler dapat menyimpannya di segmen kode.

dan ionescu
sumber
5
Saya akan mengatakan itu adalah const char [] karena sebagai nilai Anda tidak dapat memodifikasinya.
fnieto - Fernando Nieto
3

Mungkin Anda bisa mencoba ini:

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

foo("Hello")

Ini bekerja untuk saya

Alen Lee
sumber
2

Saya mengatasi masalah ini dengan menambahkan makro ini di awal kode, di suatu tempat. Atau tambahkan <iostream>, hehe.

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())
TWOPIR
sumber
8
"Atau tambahkan di <iostream>" Apa ?!
Lightness Races in Orbit
Ada ", hehe" yang untuk alasan apa pun diedit (tersirat bahwa itu adalah lelucon)
Someguynamedpie
C_TEXTtidak masalah untuk pemanggilan fungsi ( foo(C_TEXT("foo"));), tetapi menyerukan perilaku tidak terdefinisi jika nilai disimpan dalam variabel seperti char *x = C_TEXT("foo");- setiap penggunaan x(selain dari penugasan) adalah perilaku tidak terdefinisi karena memori yang ditunjuknya telah dibebaskan.
Martin Bonner mendukung Monica
1

Alasan untuk masalah ini (yang bahkan lebih sulit untuk dideteksi daripada masalah dengan char* str = "some string"- yang orang lain telah jelaskan) adalah ketika Anda menggunakan constexpr.

constexpr char* str = "some string";

Tampaknya itu akan berperilaku mirip dengan const char* str, dan karenanya tidak akan menyebabkan peringatan, seperti yang terjadi sebelumnya char*, tetapi sebaliknya berperilaku sebagai char* const str.

Detail

Pointer konstan, dan pointer ke konstanta. Perbedaannya antara const char* str, dan char* const strdapat dijelaskan sebagai berikut.

  1. const char* str: Nyatakan str untuk menjadi pointer ke const const. Ini berarti bahwa data yang menunjuk pointer ini konstan. Pointer dapat dimodifikasi, tetapi setiap upaya untuk mengubah data akan menimbulkan kesalahan kompilasi.
    1. str++ ;: VALID . Kami memodifikasi pointer, dan bukan data yang diarahkan.
    2. *str = 'a';: INVALID . Kami mencoba untuk memodifikasi data yang ditunjuk.
  2. char* const str: Nyatakan str untuk menjadi pointer const ke char. Ini berarti bahwa titik sekarang konstan, tetapi data yang ditunjukkan juga tidak. Pointer tidak dapat dimodifikasi tetapi kita dapat memodifikasi data menggunakan pointer.
    1. str++ ;: INVALID . Kami mencoba untuk memodifikasi variabel pointer, yang merupakan konstanta.
    2. *str = 'a';: VALID . Kami mencoba untuk memodifikasi data yang ditunjuk. Dalam kasus kami ini tidak akan menyebabkan kesalahan kompilasi, tetapi akan menyebabkan kesalahan runtime , karena string kemungkinan besar akan masuk ke bagian read only dari biner yang dikompilasi. Pernyataan ini akan masuk akal jika kita telah mengalokasikan memori secara dinamis, misalnya. char* const str = new char[5];.
  3. const char* const str: Deklarasikan str untuk menjadi pointer const ke char const. Dalam hal ini kita tidak dapat memodifikasi pointer, atau data yang diarahkan.
    1. str++ ;: INVALID . Kami mencoba untuk memodifikasi variabel pointer, yang merupakan konstanta.
    2. *str = 'a';: INVALID . Kami mencoba untuk memodifikasi data yang ditunjukkan oleh pointer ini, yang juga konstan.

Dalam kasus saya masalahnya adalah bahwa saya mengharapkan constexpr char* struntuk berperilaku const char* str, dan tidak char* const str, karena secara visual tampaknya lebih dekat dengan yang pertama.

Juga, peringatan yang dihasilkan constexpr char* str = "some string"sedikit berbeda dari char* str = "some string".

  1. Peringatan kompiler untuk constexpr char* str = "some string":ISO C++11 does not allow conversion from string literal to 'char *const'
  2. Peringatan compiler untuk char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.

Tip

Anda dapat menggunakan Konversi Bahasa Inggris ↔ Bahasa Inggris untuk mengonversi Cdeklarasi ke pernyataan bahasa Inggris yang mudah dimengerti, dan sebaliknya. Ini adalah satu- Csatunya alat, dan karenanya tidak akan mendukung hal-hal (seperti constexpr) yang eksklusif untuk C++.

Sahil Singh
sumber
0

Saya juga mendapat masalah yang sama. Dan apa yang saya lakukan sederhana hanya menambahkan const char * bukan char *. Dan masalah terpecahkan. Seperti yang orang lain sebutkan di atas, ini adalah kesalahan yang kompatibel. C memperlakukan string sebagai array ar sementara C ++ memperlakukan mereka sebagai array char ar.

dilantha111
sumber
0

Untuk apa nilainya, saya menemukan kelas wrapper sederhana ini berguna untuk mengubah string C ++ menjadi char *:

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

    char *getChars() {
        return &vec[0];
    }
};
bremen_matt
sumber
-1

Berikut ini mengilustrasikan solusinya, tetapkan string Anda ke pointer variabel ke array konstan char (string adalah pointer konstan ke array konstan char - plus panjang info):

#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';
}
Howard Lovatt
sumber