Conversión en desuso de C ++ de constante de cadena a 'char *'

154

Tengo una clase con un private char str[256];

y para ello tengo un constructor explícito:

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

Lo llamo como:

myClass obj("example");

Cuando compilo esto recibo la siguiente advertencia:

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

¿Por qué está pasando esto?

mkamthan
fuente
1
Debería usar en strncpy(str, func, 255)lugar de strcpy(str, func)una copia más segura. Y luego no olvide agregar el '\ 0' al final de la cadena ya que strncpy no lo agrega.
Patrice Bernassola
2
Aún más seguro decir "strncpy (str, func, sizeof (str)); str [sizeof (str) - 1] = '\ 0';"
Warren Young el
3
No creo que lo anterior dé la advertencia que citó, aunque estoy seguro de que un código bastante similar lo haría. Para obtener respuestas significativas, debe publicar un ejemplo mínimo de compilación que produzca la advertencia.
sbi
3
@Patrice, Warren: no uses strncpy, no es una versión más segura de strcpy. Use (o vuelva a implementar) strcpy_s.
Steve Jessop
Tengo el problema, solo muestra estos problemas para una compilación -X86 y no para las construcciones normales de Solaris o ARM (objetivo), así que estoy ignorando esto. No se pudo encontrar una solución aún, ya que normalmente no muestra una advertencia para mi código de muestra también. ¡Gracias a todos!
mkamthan

Respuestas:

144

Este es un mensaje de error que ve cuando tiene una situación como la siguiente:

char* pointer_to_nonconst = "string literal";

¿Por qué? Bueno, C y C ++ difieren en el tipo del literal de cadena. En C, el tipo es matriz de caracteres y en C ++ es una matriz constante de caracteres. En cualquier caso, no está permitido cambiar los caracteres del literal de cadena, por lo que la constante en C ++ no es realmente una restricción, sino más bien una cuestión de seguridad de tipo. Una conversión de const char*a char*generalmente no es posible sin un molde explícito por razones de seguridad. Pero para la compatibilidad con versiones anteriores de C, el lenguaje C ++ todavía permite asignar un literal de cadena a ay char*le da una advertencia acerca de que esta conversión está en desuso.

Entonces, en algún lugar te falta uno o más consts en tu programa para la corrección constante. Pero el código que nos mostró no es el problema, ya que no hace este tipo de conversión en desuso. La advertencia debe haber venido de otro lugar.

sellibitze
fuente
17
Es desafortunado considerando la opinión y los votos sobre esta pregunta que el OP nunca proporcionó un código que realmente demuestre el problema.
Shafik Yaghmour
1
Puede reproducir el problema con el código del OP eliminando el constdel MyClassconstructor ... luego puede solucionarlo agregando la parte constposterior.
Theodore Murdock el
145

La advertencia:

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

se da porque estás haciendo algo (no en el código que publicaste) algo como:

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

El problema es que está intentando convertir un literal de cadena (con tipo const char[]) a char*.

Puede convertir un const char[]a const char*porque la matriz se descompone en el puntero, pero lo que está haciendo es hacer que una mutable sea una constante.

Esta conversión probablemente está permitida por compatibilidad con C y solo le da la advertencia mencionada.

fnieto - Fernando Nieto
fuente
96

Como respuesta no. 2 por fnieto - Fernando Nieto describe clara y correctamente que esta advertencia se da porque en algún lugar de su código está haciendo (no en el código que publicó) algo como:

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

Sin embargo, si desea mantener su código sin advertencia también, simplemente realice los cambios respectivos en su código:

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

Es decir, simplemente emite la stringconstante a (char *).

sactiw
fuente
17
Alternativamente, realice la función: void foo (const char * str)
Caprooja
3
@Caprooja Sí, declarar el parámetro como 'puntero a una constante' también funcionará en este caso. Pero con este cambio, el usuario ya no puede cambiar / reasignar el valor almacenado en la dirección utilizando el puntero 'str' que el usuario podría estar haciendo en la parte de implementación. Entonces eso es algo que es posible que desee tener en cuenta.
Sactiw
1
@sactiw ¿Hay alguna razón para mantenerse void foo(char* str)como está? Pensé que no podemos modificar strde fooninguna manera, incluso el parámetro está escrito como no constante.
kgf3JfUtW
37

Hay 3 soluciones:

Solución 1:

const char *x = "foo bar";

Solución 2:

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

Solución 3:

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

Las matrices también se pueden usar en lugar de punteros porque una matriz ya es un puntero constante.

anilbey
fuente
77
Para la solución 3, la hay strdup. A diferencia de su código, asignará espacio para el carácter NUL de terminación y no anulará la asignación.
Ben Voigt
2
La solución 2 debe evitarse.
Carreras de ligereza en órbita
En realidad, la solución 2 puede ser: char * x = static_cast <char *> ("foo bar") en C ++.
Kehe CAI
3
Anil, ¿alguna vez integrarás los comentarios en tu respuesta? La solución 3 sigue siendo peligrosamente incorrecta.
ligereza corre en órbita el
@LightnessRacesinOrbit ¿Puede dar una respuesta? No entiendo por qué dice que las soluciones 2 y 3 deben evitarse y son peligrosamente incorrectas.
Gladclef
4

De hecho, un literal de cadena constante no es un const char * ni un char * sino un char []. Es bastante extraño, pero está escrito en las especificaciones de C ++; Si lo modifica, el comportamiento no está definido porque el compilador puede almacenarlo en el segmento de código.

dan ionescu
fuente
55
Diría que es const char [] porque como valor r no puede modificarlo.
fnieto - Fernando Nieto
3

Quizás puedas probar esto:

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

foo("Hello")

Esto funciona para mi

Alen Lee
fuente
2

Resuelvo este problema agregando esta macro al comienzo del código, en algún lugar. O <iostream>agrégalo, jeje.

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())
TWOPIR
fuente
8
"O agréguelo en <iostream>" ¡ ¿Qué ?!
ligereza corre en órbita el
Hubo ", jeje" que fue editado por cualquier razón (implicaba que era una broma)
Someguynamedpie
C_TEXTestá bien para una llamada a función ( foo(C_TEXT("foo"));), pero está pidiendo un comportamiento indefinido si el valor se almacena en una variable como char *x = C_TEXT("foo");: cualquier uso de x(aparte de la asignación) es un comportamiento indefinido porque la memoria a la que apunta se ha liberado.
Martin Bonner apoya a Mónica el
1

Una razón para este problema (que es aún más difícil de detectar que el problema con el char* str = "some string"que otros han explicado) es cuando está usando constexpr.

constexpr char* str = "some string";

Parece que se comportaría de manera similar y const char* str, por lo tanto, no causaría una advertencia, como ocurre antes char*, sino que se comporta como char* const str.

Detalles

Puntero constante y puntero a una constante. La diferencia entre const char* str, y char* const strse puede explicar de la siguiente manera.

  1. const char* str: Declara que str es un puntero a un const char. Esto significa que los datos a los que apunta este puntero son constantes. El puntero se puede modificar, pero cualquier intento de modificar los datos arrojaría un error de compilación.
    1. str++ ;: VÁLIDO . Estamos modificando el puntero, y no los datos apuntados.
    2. *str = 'a';: NO VÁLIDO . Estamos tratando de modificar los datos que se apuntan.
  2. char* const str: Declara que str es un puntero constante para char. Esto significa que el punto ahora es constante, pero los datos que se apuntan también no lo son. El puntero no se puede modificar, pero podemos modificar los datos utilizando el puntero.
    1. str++ ;: NO VÁLIDO . Estamos tratando de modificar la variable del puntero, que es una constante.
    2. *str = 'a';: VÁLIDO . Estamos tratando de modificar los datos que se apuntan. En nuestro caso, esto no causará un error de compilación, pero sí un error de tiempo de ejecución , ya que la cadena probablemente irá a una sección de solo lectura del binario compilado. Esta afirmación tendría sentido si hubiéramos asignado dinámicamente memoria, por ejemplo. char* const str = new char[5];.
  3. const char* const str: Declara que str es un puntero constante para un char constante. En este caso, no podemos modificar el puntero ni los datos a los que se apunta.
    1. str++ ;: NO VÁLIDO . Estamos tratando de modificar la variable del puntero, que es una constante.
    2. *str = 'a';: NO VÁLIDO . Estamos tratando de modificar los datos apuntados por este puntero, que también es constante.

En mi caso, el problema era que esperaba constexpr char* strcomportarme como const char* stry no char* const str, ya que visualmente parece más cercano al anterior.

Además, la advertencia generada para constexpr char* str = "some string"es ligeramente diferente de char* str = "some string".

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

Propina

Puede usar el convertidor de inglés C gibberish to para convertir Cdeclaraciones en declaraciones en inglés fácilmente comprensibles, y viceversa. Esta es una Cherramienta única y, por lo tanto, no admitirá cosas (como constexpr) que son exclusivas de C++.

Sahil Singh
fuente
0

También tengo el mismo problema. Y lo que hice simplemente fue agregar const char * en lugar de char *. Y el problema resuelto. Como otros han mencionado anteriormente, es un error compatible. C trata las cadenas como matrices de caracteres mientras que C ++ las trata como matrices de caracteres constantes.

dilantha111
fuente
0

Para lo que vale, creo que esta clase de contenedor simple es útil para convertir cadenas de C ++ a 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
fuente
-1

A continuación se ilustra la solución: asigne su cadena a un puntero variable a una matriz constante de caracteres (una cadena es un puntero constante a una matriz constante de caracteres más información de longitud):

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