Como se livrar dos avisos de `conversão obsoleta de constante de string para 'char *'` no GCC?
Pergunta
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 obsoleta de constante de string 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 fazê-los const char
ponteiros.No entanto, isso significaria tocar em 564 arquivos, no mínimo, o que não é uma tarefa que desejo realizar neste momento.O problema agora é que estou correndo com -werror
, então preciso de alguma maneira de reprimir esses avisos.Como eu posso fazer isso?
Solução
Eu acredito que passando -Wno-write-strings
para gcc suprimirá este aviso.
Outras dicas
Quaisquer funções para as quais você passa literais de string "I am a string literal"
Deveria usar char const *
como o tipo em vez de char*
.
Se você vai consertar alguma coisa, conserte direito.
Explicação:
Você não pode usar literais de string para inicializar strings que serão modificadas, porque elas são do tipo const char*
.Jogar fora a constância para depois modificá-las é comportamento indefinido, então você tem que copiar seu const char*
cordas char
por char
em alocado dinamicamente char*
strings para modificá-las.
Exemplo:
#include <iostream>
void print(char* ch);
void print(const char* ch) {
std::cout<<ch;
}
int main() {
print("Hello");
return 0;
}
Confira o gcc Pragma Diagnóstico suporte e a lista de -W opções de aviso (mudado: novo link para opções de aviso).
Para gcc, você pode usar #pragma warning
diretivas como explicadas aqui.
Eu tive um problema semelhante, resolvi 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?Eu não tenho acesso a foo
adaptá-lo para aceitar const char*
, embora essa fosse uma solução melhor (porque foo
não muda m
).
Se for uma base de código ativa, talvez você ainda queira atualizar a base de código.É claro que realizar as alterações manualmente não é viável, mas acredito que esse problema poderia ser resolvido de uma vez por todas com um único sed
comando.Eu ainda não tentei, então considere o seguinte com cautela.
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 realizar manualmente as poucas alterações restantes.
Não consigo usar a opção do compilador.Então eu transformei isso:
char *setf = tigetstr("setf");
para isso:
char *setf = tigetstr((char *)"setf");
Aqui está como fazer isso embutido em um arquivo, para que você não precise modificar seu Makefile.
// gets rid of annoying "deprecated conversion from string constant blah blah" warning
#pragma GCC diagnostic ignored "-Wwrite-strings"
Você pode então mais tarde...
#pragma GCC diagnostic pop
Substituir
char *str = "hello";
com
char *str = (char*)"hello";
ou se você estiver chamando uma função:
foo("hello");
substitua isso por
foo((char*) "hello");
Em vez de:
void foo(char *s);
foo("constant string");
Isso funciona:
void foo(const char s[]);
foo("constant string");
Em C++, use o const_cast
como abaixo
char* str = const_cast<char*>("Test string");
Test string
é uma string const.Então você pode resolver assim:
char str[] = "Test string";
ou:
const char* str = "Test string";
printf(str);
Por que não usar apenas a conversão de tipos?
(char*) "test"
Faça a conversão de tipo de string constante para ponteiro de caractere, ou seja,
char *s = (char *) "constant string";
Em C++, substitua:
char *str = "hello";
com:
std::string str ("hello");
E se você quiser comparar:
str.compare("HALLO");
Não entendo como aplicar sua solução :( – kalmanIsAGameChanger
Trabalhando com o Arduino Sketch, tive uma função que causou meus avisos.
Função original:char StrContém(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 desapareceram.
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 avisar, mas no g++ compilará, não sei por quê.
Você também pode criar uma string gravável a partir de uma constante de string chamando strdup()
.
Por exemplo, este código gera um aviso:
putenv("DEBUG=1");
No entanto, o código a seguir não (ele faz uma cópia da string no heap antes de passá-la para putenv
):
putenv(strdup("DEBUG=1"));
Neste caso (e talvez na maioria dos outros), desligar o aviso é uma má ideia – ele existe por um motivo.A outra alternativa (tornar todas as strings graváveis por padrão) é potencialmente ineficiente.
Ouça o que o compilador está lhe dizendo!
basta usar a opção -w para g++
exemplo:
g++ -w -o simples.o simples.cpp -lpthread
Lembre-se de que isso não evita a depreciação, mas evita a exibição de mensagens de aviso no terminal.
Agora, se você realmente deseja evitar a depreciação, use a palavra-chave const como esta:
const char* s="constant string";
Por que você não usa o -Wno-deprecated
opção para ignorar mensagens de aviso obsoletas?
O problema agora é que estou executando com -Werror
Este é o seu verdadeiro problema, IMO.Você pode tentar algumas maneiras automatizadas de passar de (char *) para (const char *), mas eu apostaria neles, não apenas no trabalho.Você terá que ter um humano envolvido em pelo menos parte do trabalho.No curto prazo, apenas ignore o aviso (mas deixe-o ativado na IMO ou nunca será corrigido) e apenas remova o -Werror.
Obrigado a todos pela ajuda.Escolhendo daqui e dali vem essa solução.Isso compila limpo.Ainda não testei o código.Amanhã...talvez...
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 resto foi comentado por enquanto para economizar memória.
A resposta do BlackShift é muito útil e eu a usei como:
extern string execute(char* cmd) {
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[256];
std::string result = " ";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
int main(){
char cmd[]="grep -A1 'xml' out1.txt | grep read|awk -F'=' 'BEGIN{sum=0}{sum=sum+$NF}END{print sum}'";
string result=execute(cmd);
int numOfBytes= atoi(result.c_str());
cout<<"Number of bytes = "<<numOfBytes<<endl;
return 0;
}
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 avisar, mas no g++ compilará, 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, usando macros de Boost_python
gera tais avisos.Então usamos -Wno-write-strings
ao compilar C++, pois sempre usamos -Werror