Conversione deprecata C ++ dalla costante di stringa in 'char *'


154

Ho una lezione con a private char str[256];

e per questo ho un costruttore esplicito:

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

Lo chiamo come:

myClass obj("example");

Quando compilo questo, ricevo il seguente avviso:

conversione obsoleta dalla costante di stringa in 'char *'

Perché sta succedendo?


1
Dovresti usare strncpy(str, func, 255)invece di strcpy(str, func)una copia più sicura. E quindi non dimenticare di aggiungere '\ 0' alla fine della stringa poiché strncpy non lo aggiunge.
Patrice Bernassola,

2
Ancora più sicuro dire "strncpy (str, func, sizeof (str)); str [sizeof (str) - 1] = '\ 0';"
Warren Young,

3
Non credo che quanto sopra dia l'avvertimento che hai citato, anche se sono sicuro che un codice abbastanza simile lo farebbe. Per ottenere risposte significative, è necessario pubblicare un esempio minimo e di compilazione che produca l'avviso.
sbi,

3
@Patrice, Warren: non usare strncpy, non è una versione più sicura di strcpy. Usa (o ri-implementa) strcpy_s.
Steve Jessop,

Ho riscontrato il problema, mostra solo questi problemi per una build -X86 e non per le normali build solaris o ARM (target), quindi lo sto ignorando. Impossibile trovare ancora una correzione in quanto non mostra un avviso normalmente anche per il mio codice di esempio. Grazie a tutti!
mkamthan,

Risposte:


144

Questo è un messaggio di errore che viene visualizzato ogni volta che si verifica una situazione come la seguente:

char* pointer_to_nonconst = "string literal";

Perché? Bene, C e C ++ differiscono nel tipo di stringa letterale. In C il tipo è matrice di caratteri e in C ++ è matrice costante di caratteri. In ogni caso, non ti è permesso cambiare letteralmente i caratteri della stringa, quindi la const in C ++ non è in realtà una restrizione ma più una cosa di sicurezza del tipo. Una conversione da const char*a non char*è generalmente possibile senza un cast esplicito per motivi di sicurezza. Ma per la retrocompatibilità con C il linguaggio C ++ consente ancora di assegnare una stringa letterale a char*e ti dà un avvertimento sul fatto che questa conversione è obsoleta.

Quindi, da qualche parte ti mancano una o più consts nel tuo programma per la correttezza costante. Ma il codice che ci hai mostrato non è il problema in quanto non esegue questo tipo di conversione obsoleta. L'avvertimento deve essere arrivato da qualche altra parte.


17
È un peccato considerare l'opinione e il voto su questa domanda che l'OP non ha mai fornito un codice che dimostri effettivamente il problema.
Shafik Yaghmour,

1
È possibile riprodurre il problema con il codice dell'OP eliminando constdal MyClasscostruttore ... quindi è possibile risolverlo aggiungendo il constretro.
Theodore Murdock

145

L'avviso:

conversione obsoleta dalla costante di stringa in 'char *'

è dato perché stai facendo qualcosa (non nel codice che hai pubblicato) qualcosa come:

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

Il problema è che stai provando a convertire una stringa letterale (con tipo const char[]) in char*.

È possibile convertire a const char[]in const char*perché l'array decade in puntatore, ma ciò che si sta facendo è rendere una variabile mutabile.

Questa conversione è probabilmente consentita per la compatibilità C e ti dà solo l'avvertimento menzionato.


96

Come risposta no. 2 by fnieto - Fernando Nieto descrive chiaramente e correttamente che questo avviso è dato perché da qualche parte nel tuo codice stai facendo (non nel codice che hai pubblicato) qualcosa come:

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

Tuttavia, se desideri mantenere anche il tuo codice privo di avvisi, apporta semplicemente le rispettive modifiche al codice:

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

Cioè, semplicemente lanciare la stringcostante a (char *).


17
In alternativa,
esegui

3
@Caprooja Sì, in questo caso funziona anche la dichiarazione del parametro come "puntatore a una costante". Ma con questa modifica l'utente non può più cambiare / riassegnare il valore memorizzato all'indirizzo usando il puntatore 'str' che l'utente potrebbe fare nella parte di implementazione. Quindi è qualcosa che potresti voler cercare.
Sactiw,

1
@sactiw Ci sono dei motivi per mantenere così void foo(char* str)com'è? Ho pensato che non possiamo modity strin fooogni caso, anche il parametro è scritto come non-const.
kgf3JfUtW

37

Esistono 3 soluzioni:

Soluzione 1:

const char *x = "foo bar";

Soluzione 2:

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

Soluzione 3:

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

Le matrici possono anche essere usate al posto dei puntatori perché una matrice è già un puntatore costante.


7
Per la soluzione 3, c'è strdup. A differenza del codice, alloca spazio per il carattere NUL che termina e non supera l'allocazione.
Ben Voigt,

2
La soluzione 2 deve essere evitata.
Razze di leggerezza in orbita,

In realtà la soluzione 2 può essere: char * x = static_cast <char *> ("foo bar") in C ++.
Kehe CAI,

3
Anil integrerai mai i commenti nella tua risposta? La soluzione 3 è ancora pericolosamente sbagliata.
Razze di leggerezza in orbita

@LightnessRacesinOrbit Puoi fornire una risposta per favore? Non capisco perché dici che le soluzioni 2 e 3 devono essere evitate e sono pericolosamente sbagliate.
Gladclef,

4

In effetti un letterale costante di stringa non è né un const char * né un char * ma un char []. È abbastanza strano ma annotato nelle specifiche del c ++; Se lo si modifica, il comportamento non è definito perché il compilatore potrebbe memorizzarlo nel segmento di codice.


5
Direi che è const char [] perché come valore non è possibile modificarlo.
fnieto - Fernando Nieto,

3

Forse puoi provare questo:

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

foo("Hello")

Per me funziona


2

Risolvo questo problema aggiungendo questa macro all'inizio del codice, da qualche parte. O aggiungilo <iostream>, hehe.

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

8
"O aggiungilo in <iostream>" Cosa ?!
Razze di leggerezza in orbita

C'era ", hehe" che era per qualsiasi motivo cancellato (sottintendeva che si trattava di uno scherzo)
Someguynamedpie

C_TEXTva bene per una chiamata di funzione ( foo(C_TEXT("foo"));), ma richiede un comportamento indefinito se il valore è memorizzato in una variabile come char *x = C_TEXT("foo");- qualsiasi uso di x(a parte l'assegnazione) è un comportamento indefinito perché la memoria a cui punta è stata liberata.
Martin Bonner supporta Monica il

1

Un motivo per questo problema (che è ancora più difficile da rilevare rispetto al problema con char* str = "some string"cui altri hanno spiegato) è quando si utilizza constexpr.

constexpr char* str = "some string";

Sembra che si comporterebbe in modo simile a const char* str, e quindi non causerebbe un avvertimento, come si verifica prima char*, ma invece si comporta come char* const str.

Dettagli

Puntatore costante e puntatore a una costante. La differenza tra const char* stre char* const strpuò essere spiegata come segue.

  1. const char* str: Dichiara str come puntatore a un carattere const. Ciò significa che i dati a cui questo puntatore punta puntualmente costante. Il puntatore può essere modificato, ma qualsiasi tentativo di modificare i dati genererebbe un errore di compilazione.
    1. str++ ;: VALIDO . Stiamo modificando il puntatore e non i dati indicati.
    2. *str = 'a';: INVALID . Stiamo cercando di modificare i dati indicati.
  2. char* const str: Dichiara str come puntatore const a char. Ciò significa che il punto è ora costante, ma anche i dati puntati non lo sono. Il puntatore non può essere modificato ma possiamo modificare i dati usando il puntatore.
    1. str++ ;: INVALID . Stiamo cercando di modificare la variabile puntatore, che è una costante.
    2. *str = 'a';: VALIDO . Stiamo cercando di modificare i dati indicati. Nel nostro caso ciò non causerà un errore di compilazione, ma causerà un errore di runtime , poiché la stringa molto probabilmente andrà in una sezione di sola lettura del file binario compilato. Questa affermazione avrebbe senso se avessimo allocato dinamicamente la memoria, ad es. char* const str = new char[5];.
  3. const char* const str: Dichiara str come puntatore const a un carattere const. In questo caso non possiamo né modificare il puntatore, né i dati puntati.
    1. str++ ;: INVALID . Stiamo cercando di modificare la variabile puntatore, che è una costante.
    2. *str = 'a';: INVALID . Stiamo cercando di modificare i dati puntati da questo puntatore, che è anche costante.

Nel mio caso il problema era che mi aspettavo constexpr char* strdi comportarmi come const char* str, e non char* const str, dal momento che visivamente sembra più vicino al primo.

Inoltre, l'avviso generato per constexpr char* str = "some string"è leggermente diverso da char* str = "some string".

  1. Avviso del compilatore per constexpr char* str = "some string":ISO C++11 does not allow conversion from string literal to 'char *const'
  2. Avviso del compilatore per char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.

Mancia

È possibile utilizzare il convertitore C ibberber ↔ inglese per convertire le Cdichiarazioni in dichiarazioni inglesi facilmente comprensibili e viceversa. Questo è uno Cstrumento unico e quindi non supporterà cose (come constexpr) che sono esclusive C++.


0

Ho anche avuto lo stesso problema. E quello che ho fatto è stato semplicemente aggiungere const char * invece di char *. E il problema è stato risolto. Come altri hanno già detto, si tratta di un errore compatibile. C considera le stringhe come array di caratteri mentre C ++ le tratta come array di caratteri costanti.


0

Per quello che vale, trovo che questa semplice classe wrapper sia utile per convertire stringhe C ++ in char *:

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

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

-1

Di seguito viene illustrata la soluzione, assegnare la stringa a un puntatore variabile a un array costante di char (una stringa è un puntatore costante a un array costante di char - più informazioni sulla lunghezza):

#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';
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.