Conversão descontinuada em C ++ da constante de cadeia para 'char *'

154

Eu tenho uma aula com um private char str[256];

e por isso eu tenho um construtor explícito:

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

Eu chamo como:

myClass obj("example");

Ao compilar isso, recebo o seguinte aviso:

conversão descontinuada da constante de cadeia para 'char *'

Por que isso está acontecendo?

mkamthan
fonte
1
Você deve usar em strncpy(str, func, 255)vez de strcpy(str, func)obter uma cópia mais segura. E não esqueça de adicionar o '\ 0' no final da string, pois o strncpy não o adiciona.
Patrice Bernassola 6/10/09
2
Ainda mais seguro dizer "strncpy (str, func, sizeof (str)); str [sizeof (str) - 1] = '\ 0';"
6119 Warren Young
3
Eu não acho que o que foi dito acima dá o aviso que você citou, embora eu tenha certeza de que um código bastante semelhante seria. Para obter respostas significativas, você deve postar um exemplo mínimo e compilador que produza o aviso.
Sbi #
3
@ Patricia, Warren: não use strncpy, não é uma versão mais segura do strcpy. Use (ou reimplemente) strcpy_s.
Steve Jessop
Eu entendi o problema, ele só mostra esses problemas para uma compilação -X86 e não para compilações normais do solaris ou ARM (target), por isso estou ignorando isso. Não foi possível encontrar uma correção ainda, pois não mostra um aviso normalmente para o meu código de exemplo também. Obrigado a todos!
Mkamthan 7/10/09

Respostas:

144

Esta é uma mensagem de erro que você vê sempre que tem uma situação como a seguinte:

char* pointer_to_nonconst = "string literal";

Por quê? Bem, C e C ++ diferem no tipo da string literal. Em C, o tipo é array de caracteres e, em C ++, é um array constante de caracteres. De qualquer forma, você não tem permissão para alterar os caracteres da string literal, portanto a const no C ++ não é realmente uma restrição, mas mais uma coisa de segurança de tipo. Uma conversão de const char*para char*geralmente não é possível sem uma conversão explícita por motivos de segurança. Mas, para compatibilidade com versões anteriores com C, a linguagem C ++ ainda permite atribuir uma string literal a char*e fornece um aviso sobre a descontinuação dessa conversão.

Então, em algum lugar em que você está perdendo um ou mais consts no seu programa para correção de const. Mas o código que você nos mostrou não é o problema, pois não faz esse tipo de conversão preterida. O aviso deve ter vindo de outro lugar.

sellibitze
fonte
17
É lamentável, considerando a opinião e os votos sobre esta questão, que o OP nunca forneceu código que realmente demonstrasse o problema.
Shafik Yaghmour
1
Você pode reproduzir o problema com o código do OP excluindo o constdo MyClassconstrutor ... e corrigi-lo adicionando a constparte de trás.
Theodore Murdock
145

O aviso:

conversão descontinuada da constante de cadeia para 'char *'

é dado porque você está fazendo em algum lugar (não no código que você postou) algo como:

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

O problema é que você está tentando converter uma string literal (com o tipo const char[]) em char*.

Você pode converter um const char[]para const char*porque a matriz decai para o ponteiro, mas o que você está fazendo é tornar uma mutável uma constante.

Essa conversão provavelmente é permitida para compatibilidade com C e fornece apenas o aviso mencionado.

fnieto - Fernando Nieto
fonte
96

Como resposta não. 2 por fnieto - Fernando Nieto descreve clara e corretamente que esse aviso é dado porque em algum lugar do seu código você está fazendo (não no código que você postou) algo como:

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

No entanto, se você deseja manter seu código livre de aviso, faça as alterações correspondentes no seu código:

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

Ou seja, basta lançar a stringconstante para (char *).

sactiw
fonte
17
Alternativamente, fazer a função: void foo (const char * str)
Caprooja
3
@ Caprooja Sim, declarar o parâmetro como 'ponteiro para uma constante' também funcionará neste caso. Mas com essa alteração, o usuário não pode mais alterar / reatribuir o valor armazenado no endereço usando o ponteiro 'str' que o usuário pode estar executando na parte de implementação. Então, isso é algo que você pode querer procurar.
sactiw
1
@sactiw Existem razões para continuar void foo(char* str)como está? Eu pensei que não podemos modificar strde fooqualquer maneira, mesmo o parâmetro é escrito como não-const.
kgf3JfUtW
37

Existem 3 soluções:

Solução 1:

const char *x = "foo bar";

Solução 2:

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

Solução 3:

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

Matrizes também podem ser usadas em vez de ponteiros, porque uma matriz já é um ponteiro constante.

anilbey
fonte
7
Para a solução 3, existe strdup. Diferentemente do seu código, ele alocará espaço para o caractere NUL final e não excederá a alocação.
Ben Voigt
2
A solução 2 deve ser evitada.
Lightness Races em órbita
Na verdade, a solução 2 pode ser: char * x = static_cast <char *> ("foo bar") em C ++.
Kehe CAI
3
Você já integrou os comentários na sua resposta? A solução 3 ainda está perigosamente errada.
Lightness Races in Orbit
@LightnessRacesinOrbit Você pode fornecer uma resposta? Não entendo por que você diz que as soluções 2 e 3 devem ser evitadas e estão perigosamente erradas.
Gladclef 17/05/19
4

De fato, uma constante de string literal não é um const char * nem um char *, mas um char []. É bastante estranho, mas escrito nas especificações c ++; Se você modificá-lo, o comportamento é indefinido porque o compilador pode armazená-lo no segmento de código.

dan ionescu
fonte
5
Eu diria que é const char [] porque como um rvalue você não pode modificá-lo.
fnieto - Fernando Nieto 6/10/09
3

Talvez você possa tentar o seguinte:

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

foo("Hello")

Funciona para mim

Alen Lee
fonte
2

Eu resolvo esse problema adicionando essa macro no início do código, em algum lugar. Ou adicione <iostream>, hehe.

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())
TWOPIR
fonte
8
"Ou adicione-o no <iostream>" O quê ?!
Lightness Races in Orbit
Houve "hehe" que foi por qualquer motivo editado (implícito que era uma piada)
Someguynamedpie
C_TEXTé bom para uma chamada de função ( foo(C_TEXT("foo"));), mas clama por comportamento indefinido se o valor for armazenado em uma variável como char *x = C_TEXT("foo");- qualquer uso de x(além da atribuição) é um comportamento indefinido porque a memória para a qual está apontando foi liberada.
Martin Bonner apoia Monica
1

Uma razão para esse problema (que é ainda mais difícil de detectar do que o problema char* str = "some string"- que outros explicaram) é quando você está usando constexpr.

constexpr char* str = "some string";

Parece que ele se comportaria de maneira semelhante e const char* str, portanto, não causaria um aviso, como ocorre antes char*, mas se comportaria como char* const str.

Detalhes

Ponteiro constante e ponteiro para uma constante. A diferença entre const char* stre char* const strpode ser explicada da seguinte forma.

  1. const char* str: Declare str como um ponteiro para um const char. Isso significa que os dados para os quais esse ponteiro está apontando para ele são constantes. O ponteiro pode ser modificado, mas qualquer tentativa de modificar os dados geraria um erro de compilação.
    1. str++ ;: VÁLIDO . Estamos modificando o ponteiro, e não os dados que estão sendo apontados.
    2. *str = 'a';: INVÁLIDO . Estamos tentando modificar os dados que estão sendo apontados.
  2. char* const str: Declare str como um ponteiro const para char. Isso significa que agora o ponto é constante, mas os dados também estão sendo apontados. O ponteiro não pode ser modificado, mas podemos modificar os dados usando o ponteiro.
    1. str++ ;: INVÁLIDO . Estamos tentando modificar a variável ponteiro, que é uma constante.
    2. *str = 'a';: VÁLIDO . Estamos tentando modificar os dados que estão sendo apontados. No nosso caso, isso não causará um erro de compilação, mas causará um erro de tempo de execução , pois a string provavelmente entrará em uma seção somente leitura do binário compilado. Essa afirmação faria sentido se alocássemos memória dinamicamente, por exemplo. char* const str = new char[5];.
  3. const char* const str: Declare str como um ponteiro const para um const char. Nesse caso, não podemos modificar o ponteiro, nem os dados que estão sendo apontados.
    1. str++ ;: INVÁLIDO . Estamos tentando modificar a variável ponteiro, que é uma constante.
    2. *str = 'a';: INVÁLIDO . Estamos tentando modificar os dados apontados por esse ponteiro, que também é constante.

No meu caso, a questão era que eu esperava constexpr char* strme comportar como const char* str, e não char* const str, já que visualmente parece mais próximo do primeiro.

Além disso, o aviso gerado para constexpr char* str = "some string"é um pouco diferente de char* str = "some string".

  1. Aviso do compilador para constexpr char* str = "some string":ISO C++11 does not allow conversion from string literal to 'char *const'
  2. Aviso do compilador para char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.

Dica

Você pode usar o conversor C gibberish ↔ English para converter Cdeclarações em instruções inglesas facilmente compreensíveis e vice-versa. Esta é uma Cúnica ferramenta e, portanto, não suporta coisas (como constexpr) que são exclusivas C++.

Sahil Singh
fonte
0

Eu também tenho o mesmo problema. E o que eu fiz foi apenas adicionar const char * em vez de char *. E o problema resolvido. Como outros já mencionaram acima, é um erro compatível. C trata as strings como matrizes de caracteres, enquanto o C ++ as trata como matrizes const char.

dilantha111
fonte
0

Quanto vale a pena, acho que essa classe simples de wrapper é útil para converter cadeias de caracteres C ++ em 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
fonte
-1

A seguir, ilustra a solução, atribua sua string a um ponteiro variável a uma matriz constante de char (uma string é um ponteiro constante a uma matriz constante de char - além de informações de comprimento):

#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
fonte