¿Cómo deshacerse de las advertencias de conversión obsoleta de constante de cadena a 'char *' en GCC?


409

Así que estoy trabajando en una base de código extremadamente grande, y recientemente me actualicé a gcc 4.3, que ahora activa esta advertencia:

advertencia: conversión obsoleta de constante de cadena a 'char *'

Obviamente, la forma correcta de solucionar esto es encontrar cada declaración como

char *s = "constant string";

o llamada de función como:

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

y hazlos const charpunteros. Sin embargo, eso significaría tocar 564 archivos, como mínimo, que no es una tarea que deseo realizar en este momento. El problema en este momento es que estoy corriendo -werror, así que necesito alguna forma de sofocar estas advertencias. ¿Cómo puedo hacer eso?


Cuando tratas de reemplazar 554 líneas, sed es un buen amigo. Sin embargo, asegúrese de hacer una copia de seguridad primero.
Matt

2
Miré las discusiones sobre cómo suprimir los mensajes de error y cuáles deberían ser los reemplazos correctos. No tengo ninguna opinión al respecto. Sin embargo, creo que Matt está en el camino correcto. Defina lo que desea reemplazar por qué. Solo necesita las expresiones regulares correctas. Haz los cambios en una copia. Use "diff" para compararlos con el original. Hacer los cambios usando sed es rápido, fácil y gratis, y diff también es rápido, fácil y gratis. Pruébelo y vea cuántos cambios tiene que revisar. Publique lo que desea reemplazar por qué y permita que los usuarios sugieran reemplazos de expresiones regulares.
Thomas Hedden

En toda la discusión se pierde el punto de por qué este es un problema que debe solucionarse de acuerdo con la advertencia de gcc. La razón está en la respuesta de David Schwartz stackoverflow.com/questions/56522654/… .
andig

Respuestas:


227

Creo que pasar -Wno-write-stringsa gcc suprimirá esta advertencia.


66
¿Se puede deshabilitar en por archivo básico usando pragmas?
Priyank Bolia

18
@PriyankBolia bdonlan comentó sobre la respuesta de Rob Walker que puede usar #pragma GCC diagnostic ignored "-Wwrite-strings".
MasterMastic

99
Excepto si controla la API, en cuyo caso la respuesta de @ John a continuación, sobre cambiar la firma para aceptar const char *, es más correcto.
jcwenger

215
ESTA ES UNA PRACTICA HORRIBLEMENTE MALA, y estoy triste porque obtuvo todos esos votos. Las advertencias no están ahí para que las ignore. Hay advertencias que te dicen "amigo, estás haciendo algo que podría estar mal, ten cuidado", y solo debes suprimirlas cuando quieras responder como "cállate, sé lo que estoy haciendo", lo cual es muy probable No es el caso de los programadores infantiles.
The Quantum Physicist

99
Estoy de acuerdo, no debes deshacerte de la advertencia y en su lugar usar la solución provista por John. ¡Lástima que esta sea la respuesta aceptada!
Jérôme

564

Cualquier función en la que pase literales de cadena "I am a string literal"debe usar char const *como tipo en lugar de char*.

Si vas a arreglar algo, arréglalo bien.

Explicación:

No puede usar literales de cadena para inicializar cadenas que se modificarán, porque son de tipo const char*. Desechar los constness modificar más adelante ellos es un comportamiento indefinido , por lo que tiene que copiar sus const char*cadenas charpor chardentro asignados dinámicamente char*las cadenas con el fin de modificarlos.

Ejemplo:

#include <iostream>

void print(char* ch);

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

int main() {
    print("Hello");
    return 0;
}

25
Si bien esto es cierto, no siempre tienes control sobre las API de terceros que podrían no usar correctamente char */ const char *, por lo que en ese caso normalmente lanzo.
ideasman42

15
@ppumkin Desafortunadamente, muchas funciones de cadena de biblioteca estándar de C toman argumentos como char*incluso para cadenas que no se modificarán. Si tomas un parámetro como a char const*y lo pasas a una función estándar tomando un char*, golpearás eso. Si la función de biblioteca no manipulará la cadena, puede desechar la const.
John

El hecho de que no siempre sea posible no significa que no sea la opción preferida para muchas de las veces que esta advertencia aparece en el código de producción común.
LovesTha

1
Ahora entiendo completamente la solución y la funcionalidad de los literales de cadena. Pero tal vez otros no, así que 'sostengo' la necesidad de una explicación
NicoBerrogorry

1
No entiendo cómo aplicar su solución :(
desmond13

69

Tuve un problema similar, lo resolví así:

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

¿Es esta una forma apropiada de resolver esto? No tengo acceso para fooadaptarlo para aceptar const char*, aunque esa sería una mejor solución (porque foono cambia m).


8
@elcuco, ¿qué propondrías? No pude editar foo e intenté encontrar una solución que no requiriera la supresión de la advertencia. En mi caso, esto último fue más una cuestión de ejercicio, pero para el póster original parecía importante. Por lo que puedo decir, mi respuesta es la única que resolvería las condiciones tanto de mí como del OP al mismo tiempo, por lo que podría ser una respuesta valiosa para alguien. Si cree que mi solución no es lo suficientemente buena, ¿podría proporcionar una alternativa? (Eso no incluye editar foo o ignorar la advertencia.)
BlackShift

si suponemos que foo está codificado correctamente (lo que desafortunadamente no parece ser el caso del código del que habla 'Josh Matthews'), esta es la mejor solución. eso es porque si la función necesita cambiar la cadena 'msg' pasándola, una cadena constante rompería el código, ¿verdad? pero de todos modos, esto no parece responder a la pregunta porque los errores ya están en el código anterior y no en el nuevo, por lo que necesitaría cambiar el código anterior de todos modos.
João Portela el

Ese es el enfoque que tomé también. Y si alguien está buscando esto para los casos de char **en PyArg_ParseTupleAndKeywords, hago algo como esto:static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};
guiones

@elcuco: no estoy seguro de cómo funcionan las matrices estáticas de C ++. ¿Esto realmente copiará algún dato, y no solo el puntero?
Alexander Malakhov

Si bien este enfoque puede tener mérito en algunos casos, aplicarlo a ciegas es probable que la OMI haga más daño que bien. Aplicar esto a ciegas podría conducir fácilmente a punteros colgantes. También hinchará el código con copias de cadenas sin sentido.
enchufe


30

Si se trata de una base de código activa, es posible que aún desee actualizar la base de código. Por supuesto, realizar los cambios manualmente no es factible, pero creo que este problema podría resolverse de una vez por todas con un solo sedcomando. Sin embargo, no lo he probado, así que toma lo siguiente con un grano de sal.

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

Es posible que esto no encuentre todos los lugares (incluso sin considerar las llamadas a funciones), pero aliviará el problema y permitirá realizar los pocos cambios restantes manualmente.


77
eso solo resuelve advertencias de declaraciones y no llamadas de función +1 para sed fu de todos modos: p
João Portela

25

No puedo usar el interruptor del compilador. Entonces he convertido esto:

char *setf = tigetstr("setf");

a esto:

char *setf = tigetstr((char *)"setf");

1
+1: no puede cambiar el valor de las aplicaciones, solo el valor. Esto demostró solucionar el problema real. otros solo resuelven algunos problemas con el compilador.
elcuco

1
Lo que es realmente molesto es que tigetstr () debe ser un prototipo con un (const char *), no un (char *)
vy32

2
Cuando hago esto recibo "advertencia: en cambio, desde el tipo 'const char *' hasta el tipo 'char *' desecha la constidad '. Tuve que usar un const_cast para deshacerme de todas las advertencias: const_cast <char *> ("setf")
CrouZ

2
Creo que const cast es la primera solución aceptable en esta página (excepto el cambio de API).
rwst

25

Aquí se explica cómo hacerlo en línea en un archivo, para que no tenga que modificar su Makefile.

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

Luego puedes ...

#pragma GCC diagnostic pop

25

Reemplazar

char *str = "hello";

con

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

o si está llamando a la función:

foo("hello");

reemplazar esto con

foo((char*) "hello");

15

En vez de:

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

Esto funciona:

void foo(const char s[]);
foo("constant string");

¡Esta es la forma correcta de hacerlo, ya que no debe pasar una cadena (constante) a una función que espera una cadena no constante de todos modos!
jfla

15

En C ++, use lo const_castque se muestra a continuación

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

7

Test stringes una cadena constante. Entonces puedes resolver así:

char str[] = "Test string";

o:

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

4

¿Por qué no solo usar el tipo de fundición?

(char*) "test"

2

Realice la conversión de texto de cadena constante a puntero de caracteres, es decir

char *s = (char *) "constant string";

1

En C ++, Reemplace:

char *str = "hello";

con:

std::string str ("hello");

Y si quieres compararlo:

str.compare("HALLO");

1

No entiendo cómo aplicar su solución :( - kalmanIsAGameChanger

Trabajando con Arduino Sketch, tenía una función que causaba mis advertencias.

Función original: char StrContains (char * str, char * sfind)

Para detener las advertencias, agregué el const delante del char * str y el char * sfind.

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

Todas las advertencias se fueron.


Esta es la respuesta correcta según la advertencia decía: "advertencia: conversión obsoleta de constante de cadena a 'char *'".
Norbert Boros

0

ver esta situación:

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

mire el campo de nombre, en gcc se compila sin advertencia, pero en g ++ lo hará, no sé por qué.


gcc implica tratar el archivo como un archivo fuente de C, g ++ tratarlo como un archivo fuente de C ++, a menos que sea anulado por -x ?? opción. Entonces, un lenguaje diferente, c y c ++ tiene diferencias sutiles sobre lo que debería ser una advertencia.
zhaorufei

0

También puede crear una cadena de escritura desde una constante de cadena llamando strdup().

Por ejemplo, este código genera una advertencia:

putenv("DEBUG=1");

Sin embargo, el siguiente código no lo hace (hace una copia de la cadena en el montón antes de pasarlo putenv):

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

En este caso (y quizás en la mayoría de los demás), desactivar la advertencia es una mala idea, está ahí por una razón. La otra alternativa (hacer que todas las cadenas se puedan escribir de manera predeterminada) es potencialmente ineficiente.

¡Escucha lo que te dice el compilador!


66
Y también pierde la memoria asignada para esa cadena de escritura.
RBerteig 05 de

1
Sí, lo hace a propósito. No es un problema con el código de una sola vez (por ejemplo, inicialización), como se indicó anteriormente. O bien, puede administrar la memoria usted mismo y liberarla cuando haya terminado con ella.
BillAtHRST

1
El caso particular de putenv()está lleno: no es una buena opción de ejemplo (al menos, no sin mucha más discusión sobre lo que putenv()hace que en esta respuesta). Es una discusión completamente separada. (Tenga en cuenta que la especificación POSIX para el comportamiento de putenv()es problemática, en base a las implementaciones heredadas de antes de que se definiera POSIX). IIRC, hubo un error en una versión reciente (este milenio) de GNU C Library que estaba relacionado con el putenv()cambio de comportamiento, y ser cambiado de nuevo.)
Jonathan Leffler

0

solo usa la opción -w para g ++

ejemplo:

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

Recuerde que esto no evita la desaprobación, sino que evita mostrar mensajes de advertencia en el terminal.

Ahora, si realmente desea evitar la degradación, use la palabra clave const como esta:

const char* s="constant string";  

0

¿Por qué no utiliza la -Wno-deprecatedopción para ignorar los mensajes de advertencia obsoletos?


0

El problema ahora es que estoy ejecutando con -Werror

Este es tu verdadero problema, OMI. Puede probar algunas formas automatizadas de pasar de (char *) a (const char *), pero yo pondría dinero en ellas no solo trabajando. Tendrá que involucrar a un humano para al menos parte del trabajo. A corto plazo, simplemente ignore la advertencia (pero IMO la deja activada, o nunca se solucionará) y simplemente elimine -Werror.


99
La razón la gente utiliza -Werror es por lo que las advertencias no se arreglen. De lo contrario, nunca se arreglan.
Zan Lynx

2
La razón por la que las personas usan -Werror es porque solo han trabajado en proyectos de juguetes, o son masoquistas. Hacer que su código no se cree debido a una actualización de GCC es un problema real cuando tiene 100k + LOC. Dito alguien agregando basura como "-Wno-write-strings" a la compilación para deshacerse de las advertencias molestas (como sugiere el comentario mejor calificado en esta publicación).
James Antill

2
Hay un claro desacuerdo en ese tema, por ejemplo, programador.97things.oreilly.com/wiki/index.php/…
João Portela

3
@ James: Haces un punto interesante, pero tiene que haber una mejor manera. Parece inútil no reparar las advertencias de inmediato: ¿cómo se reconoce cuando el nuevo código ha invocado una nueva advertencia cuando no ha eliminado todas las advertencias anteriores? En mi experiencia, eso solo lleva a las personas a ignorar las advertencias de que no deberían ignorar.
nobar

2
@ James: nuestro proyecto de juguete es 1.5 + M LOC (multi-idioma). Como dijo nobar, -Werror evita ignorar las advertencias que no deberían ser, y sí, cada vez que surge una nueva versión del compilador, debemos volver a verificar todo. -Wno-write-strings solo se usa cuando se usa Boost para envoltorios de python en un archivo por archivo, porque no vamos a reescribir Boost (y en este momento, 2017, preferimos no usar más Boost sino C ++ 11 / cython) Cada advertencia ignorada debe revisarse periódicamente mediante un control de calidad para ver si ahora se puede evitar mediante código o si aún no es posible.
msn

0

Gracias por toda la ayuda. Escogiendo de aquí para allá viene esta solución. Esto compila limpio. No he probado el código todavía. Mañana tal vez...

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 }

Lo sé, solo hay 1 elemento en la matriz timeServer. Pero podría haber más. El resto fueron comentados por ahora para ahorrar memoria.


-1
PyTypeObject PyDict_Type=
{ ...

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

mire el campo de nombre, en gcc se compila sin advertencia, pero en g ++ lo hará, no sé por qué.

en gcc (Compiling C), -Wno-write-strings está activo por defecto.

en g++ (Compiling C++)-Wwrite-strings está activo por defecto

Por eso hay un comportamiento diferente. Para nosotros, el uso de macros de Boost_pythongenera tales advertencias. Entonces usamos -Wno-write-stringscuando compilamos C ++ ya que siempre usamos-Werror


-1

Declarar cadena como a constresolverá el problema:

char const*s = "constant string";
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.