Como se livrar de avisos de `conversão obsoleta da constante de cadeia de caracteres para 'char *' 'no GCC?

409

Então, eu estou trabalhando em uma base de código extremamente grande e atualizei recentemente para o gcc 4.3, que agora aciona este aviso:

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

Obviamente, a maneira correta de corrigir isso é encontrar todas as declarações como

char *s = "constant string";

ou chamada de função como:

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

e torná-los const charponteiros. No entanto, isso significaria tocar no mínimo 564 arquivos, o que não é uma tarefa que desejo executar neste momento. O problema agora é que estou enfrentando -werror, por isso preciso de alguma maneira de reprimir esses avisos. Como eu posso fazer isso?

Josh Matthews
fonte
Quando você tenta substituir 554 linhas, sed é um bom amigo. Certifique-se de fazer o backup primeiro.
Matt
2
Examinei as discussões sobre como suprimir as mensagens de erro e quais deveriam ser as substituições corretas. Eu não tenho nenhuma opinião sobre isso. No entanto, acho que Matt está no caminho certo. Defina o que você deseja substituir por quê. Você só precisa das expressões regulares corretas. Faça as alterações em uma cópia. Use "diff" para compará-los com o original. Fazer as alterações usando o sed é rápido, fácil e gratuito, e o diff também é rápido, fácil e gratuito. Experimente e veja quantas alterações você precisa revisar. Poste o que deseja substituir por quê e permita que os usuários sugiram substituições de regex.
Thomas Hedden
Toda a discussão está faltando o motivo pelo qual este é um problema que precisa ser corrigido de acordo com o aviso do gcc. O motivo está na resposta de David Schwartz stackoverflow.com/questions/56522654/… .
andig

Respostas:

227

Acredito que -Wno-write-stringsa passagem para o gcc suprimirá esse aviso.

DGentry
fonte
6
Pode ser desativado por arquivo básico usando pragmas.
Priyank Bolia
18
@PriyankBolia bdonlan comentou a resposta de Rob Walker que pode ser usada #pragma GCC diagnostic ignored "-Wwrite-strings".
MasterMastic
9
Exceto se você controlar a API, nesse caso a resposta de John abaixo, sobre a alteração da assinatura para aceitar const char *, é mais correto.
Jcwenger
215
ISTO É UMA PRÁTICA HORRÍVEL, MAU, e estou triste por ter todos esses votos. Os avisos não existem para que você os ignore. Existem avisos dizendo "cara, você está fazendo algo que pode estar errado, tenha cuidado", e você só deve suprimi-los quando quiser responder como "cale a boca, eu sei o que estou fazendo", o que é mais provável não é o caso de programadores infantis.
A Quantum Físico
9
Concordo que você não deve se livrar do aviso e usar a solução fornecida por John. Pena que esta é a resposta aceita!
Jérôme
564

Quaisquer funções nas quais você passa literais de seqüência de caracteres "I am a string literal"devem ser usadas char const *como o tipo em vez de char*.

Se você estiver consertando algo, conserte certo.

Explicação:

Você não pode usar literais de cadeia para inicializar cadeias que serão modificadas, porque são do tipo const char*. Erradicação dos constness para modificá-los mais tarde é um comportamento indefinido , então você tem que copiar suas const char*cordas charpor charem alocação dinâmica char*cordas, a fim de modificá-los.

Exemplo:

#include <iostream>

void print(char* ch);

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

int main() {
    print("Hello");
    return 0;
}
John
fonte
25
Embora isso seja verdade, você nem sempre tem controle sobre APIs de terceiros que podem não usar corretamente char */ const char *, portanto, nesse caso, eu normalmente transmito.
usar o seguinte código
15
@ppumkin Infelizmente, muitas funções de string da biblioteca C padrão aceitam argumentos char*mesmo para strings que não serão modificados. Se você pegar um parâmetro como a char const*e passá-lo para uma função padrão, pegue um char*. Se a função da biblioteca não estiver manipulando a string, você poderá eliminar o const.
John
Só porque nem sempre é possível, não significa que não seja a opção preferida em muitas vezes que esse aviso aparece no código de produção comum.
LovesTha
1
Agora eu entendo completamente a solução e a funcionalidade de literais de string. Mas talvez outros não, então eu "mantenho" a necessidade de uma explicação
NicoBerrogorry
1
Não sei como aplicar sua solução :(
desmond13
69

Eu tive um problema semelhante, resolvi-o assim:

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

Esta é uma maneira apropriada de resolver isso? Não tenho acesso para fooadaptá-lo para aceitar const char*, embora isso seria uma solução melhor (porque foonão muda m).

BlackShift
fonte
8
@elcuco, o que você propõe? Não consegui editar o foo e tentei encontrar uma solução que não exigisse a supressão do aviso. No meu caso, o último era mais uma questão de exercício, mas para o pôster original parecia importante. Pelo que sei, minha resposta é a única que resolveria as condições do meu e do OP ao mesmo tempo, para que pudesse ser uma resposta valiosa para alguém. Se você acha que minha solução não é boa o suficiente, você poderia fornecer uma alternativa? (Isso não inclui a edição foo ou ignorar o aviso.)
BlackShift
se assumirmos que foo é codificado corretamente (o que infelizmente não parece ser o caso do código que 'Josh Matthews' está falando), essa é a melhor solução. isso porque se a função precisa realmente alterar a string 'msg' passando uma string constante, ele quebraria o código, certo? de qualquer maneira, isso parece não responder à pergunta porque os erros já estão no código antigo e não no novo, portanto, ele precisaria alterar o código antigo de qualquer maneira.
João Portela
Essa é a abordagem que eu também adotei. E se alguém está pesquisando isso nos casos de char **in PyArg_ParseTupleAndKeywordseu faço algo parecido com isto:static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};
traço
@elcuco: Não tenho certeza de como as matrizes estáticas C ++ funcionam. Isso realmente copiará quaisquer dados, e não apenas ponteiro?
Alexander Malakhov
Embora essa abordagem possa ter mérito em alguns casos, aplicá-la às cegas é provável que a OMI faça mais mal do que bem. Aplicar isso cegamente pode facilmente levar a indicadores pendentes. Ele também inchará o código com cópias inúteis de strings.
plugwash
30

Se for uma base de código ativa, você ainda poderá atualizar a base de código. Obviamente, executar as alterações manualmente não é viável, mas acredito que esse problema possa ser resolvido de uma vez por todas por um único sedcomando. Eu não tentei, no entanto, então faça o seguinte com um grão de sal.

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

Isso pode não encontrar todos os locais (mesmo sem considerar as chamadas de função), mas aliviaria o problema e tornaria possível executar as poucas alterações restantes manualmente.

Konrad Rudolph
fonte
7
que não só resolve declarações avisos e não chamadas de função +1 para fu sed de qualquer maneira: p
João Portela
25

Não consigo usar a opção de compilador. Então eu virei isso:

char *setf = tigetstr("setf");

para isso:

char *setf = tigetstr((char *)"setf");
vy32
fonte
1
+1 - você não pode alterar o valor das aplicações, apenas o valor. isso provou corrigir o problema real. outro apenas soluciona alguns problemas com o compilador.
elcuco
1
A única coisa que é realmente irritante é que tigetstr () deve ser um protótipo com um (const char *), não um (char *)
vy32
2
Quando faço isso, recebo "warning: cast from type 'const char *' to type 'char *' elimina constness". Eu tive que usar um const_cast para se livrar de todos os avisos: const_cast <char *> ("setf")
CrouZ 5/15
2
Eu acho que o elenco constante é a primeira solução aceitável nesta página (exceto a alteração da API).
rwst
25

Aqui está como fazer isso em linha em um arquivo, para que você não precise modificar o Makefile.

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

Você pode depois ...

#pragma GCC diagnostic pop
EdH
fonte
25

Substituir

char *str = "hello";

com

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

ou se você estiver chamando na função:

foo("hello");

substitua isso por

foo((char*) "hello");
Takataka
fonte
15

Ao invés de:

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

Isso funciona:

void foo(const char s[]);
foo("constant string");
John
fonte
Esta é a maneira correta de fazer isso, pois você não deve passar uma string (constante) para uma função que espera uma string não constante de qualquer maneira!
jfla
15

Em C ++, use o const_castcomo abaixo

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

Test stringé const string. Então você pode resolver assim:

char str[] = "Test string";

ou:

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

Por que não usar apenas conversão de tipo?

(char*) "test"
Dario
fonte
2

Faça a conversão de tipos de letra constante para ponteiro char, ou seja,

char *s = (char *) "constant string";
tejp124
fonte
1

Em C ++, substitua:

char *str = "hello";

com:

std::string str ("hello");

E se você quiser compará-lo:

str.compare("HALLO");
Sohrab
fonte
1

Não entendo como aplicar sua solução :( - kalmanIsAGameChanger

Trabalhando com o Arduino Sketch, eu tinha uma função causando meus avisos.

Função original: char StrContains (char * str, char * sfind)

Para interromper os avisos, adicionei o const na frente do char * str e do char * sfind.

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

Todos os avisos foram embora.

MyGEARStationcom
fonte
Esta é a resposta correta, de acordo com o aviso: "aviso: conversão descontinuada da constante da string para 'char *'".
Norbert Boros
0

veja esta situação:

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

observe o campo name, no gcc ele compila sem aviso, mas no g ++ ele vai, não sei por quê.

shindow
fonte
gcc implica tratar o arquivo como arquivo de origem C, g ++ trata-o como arquivo de origem c ++, a menos que seja substituído por -x ?? opção. Portanto, linguagens diferentes, c e c ++ apresentam diferenças sutis sobre o que deveria ser um aviso.
Zhaorufei
0

Você também pode criar uma sequência de caracteres gravável a partir de uma constante de sequência chamando strdup().

Por exemplo, este código gera um aviso:

putenv("DEBUG=1");

No entanto, o código a seguir não faz (ele faz uma cópia da sequência na pilha antes de passá-la para putenv):

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

Nesse caso (e talvez na maioria dos outros), desligar o aviso é uma má idéia - existe por um motivo. A outra alternativa (tornar todas as seqüências de caracteres graváveis ​​por padrão) é potencialmente ineficiente.

Ouça o que o compilador está dizendo!

BillAtHRST
fonte
6
E também vaza a memória alocada para essa sequência gravável.
RBerteig
1
Sim, sim - isso é de propósito. Não é um problema com o código único (por exemplo, inicialização), como acima. Ou, você mesmo pode gerenciar a memória e liberá-la quando terminar.
BillAtHRST 20/06/09
1
O caso particular de putenv()é cheio - não é uma boa escolha de exemplo (pelo menos, não sem muito mais discussão sobre o que putenv()faz do que existe nesta resposta). É toda uma discussão separada. (Observe que a especificação POSIX para o comportamento de putenv()é problemática, com base nas implementações herdadas anteriores à definição do POSIX.) IIRC, houve um bug em uma versão recente (neste milênio) da GNU C Library que estava relacionada à putenv()mudança de comportamento, e sendo alterado novamente).
Jonathan Leffler
0

basta usar a opção -w para g ++

exemplo:

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

Lembre-se de que isso não evita a descontinuação, mas evita a exibição de uma mensagem de aviso no terminal.

Agora, se você realmente deseja evitar a descontinuação, use a palavra-chave const como esta:

const char* s="constant string";  
Mestre Arafat Al Mahmud
fonte
0

Por que você não usa a -Wno-deprecatedopção para ignorar mensagens de aviso obsoletas?

Drew Noakes
fonte
0

O problema agora é que estou executando com -Werror

Este é seu verdadeiro problema, IMO. Você pode tentar algumas maneiras automatizadas de passar de (char *) para (const char *), mas eu colocaria dinheiro nelas não apenas trabalhando. Você terá que ter um humano envolvido por pelo menos parte do trabalho. No curto prazo, ignore o aviso (mas o IMO o deixe ativado ou ele nunca será corrigido) e remova o erro -Werror.

James Antill
fonte
9
A razão pela qual as pessoas usam -Werror é para que os avisos não ficar fixo. Caso contrário, eles nunca serão consertados.
Zan Lynx
2
A razão pela qual as pessoas usam -Werror é porque elas só trabalharam em projetos de brinquedos ou são masoquistas. A falha na criação do seu código devido a uma atualização do GCC é um problema real quando você tem 100k + LOC. Dito. alguém adicionando lixo eletrônico como "-Wno-write-strings" à compilação para se livrar dos avisos irritantes (como sugere o comentário mais bem avaliado neste post).
James Antill
2
há um desacordo claro nesse tópico, por exemplo programmer.97things.oreilly.com/wiki/index.php/…
João Portela
3
@ James: Você faz uma observação interessante, mas deve haver uma maneira melhor. Parece inútil não corrigir avisos imediatamente - como você reconhece quando o novo código invoca um novo aviso quando você não removeu todos os avisos antigos? Na minha experiência, isso apenas leva as pessoas a ignorarem avisos que não deveriam estar ignorando.
Nobar
2
@ James: nosso projeto de brinquedos é 1.5 + M LOC (multilíngue). Como nobar disse, -Werror evita ignorar avisos que não deveriam ser e sim, cada vez que uma nova versão do compilador sobe, devemos verificar novamente tudo. -Wno-write-strings é usado apenas ao usar o Boost para wrappers python em um arquivo por arquivo, porque não vamos reescrever o Boost (e, no momento, em 2017, preferimos não usar mais o Boost, mas o C ++ 11 / cython). Cada aviso ignorado deve ser revisado periodicamente por uma verificação de qualidade para ver se agora eles podem ser evitados por código ou se ainda não é possível.
msn
0

Obrigado a todos pela ajuda. Escolhendo daqui e de lá vem esta solução. Isso compila limpo. Ainda não testei o código. Talvez amanhã...

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 }

Eu sei, há apenas 1 item na matriz timeServer. Mas poderia haver mais. O restante foi comentado por enquanto para economizar memória.

Micheal Morrow
fonte
-1
PyTypeObject PyDict_Type=
{ ...

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

observe o campo name, no gcc ele compila sem aviso, mas no g ++ ele vai, não sei por quê.

em gcc (Compiling C), -Wno-write-strings está ativo por padrão.

em g++ (Compiling C++)-Wwrite-strings está ativo por padrão

É por isso que existe um comportamento diferente. Para nós, usar macros de Boost_pythongera esses avisos. Então, usamos -Wno-write-stringsao compilar C ++, pois sempre usamos-Werror

msn
fonte
-1

Declare a string como a constresolverá o problema:

char const*s = "constant string";
Jaa Hsn
fonte