c++ - una - volatile in c plus plus
¿Por qué ostream imprime `1` para una cadena definida como` volatile char[] `? (4)
Esta pregunta ya tiene una respuesta aquí:
Considera este ejemplo (artificial):
#include <cstdio>
#include <iostream>
int main() {
volatile char test[] = "abc";
std::printf("%s/n", test);
std::cout << test << "/n";
}
Compilarlo con GCC y ejecutarlo da el siguiente resultado:
$ g++ test.cc
$ ./a.out
abc
1
Como puede ver, printf
imprime la cadena correctamente mientras que cout
imprime 1
. ¿Por qué escribir a cout
produce 1
en este caso?
Es el calificador volatile
que lo convierte en un bool
, intente en su lugar:
std::cout << const_cast<char*>(test) << "/n";
La única sobrecarga adecuada del operator<<
es la de bool
, por lo que la matriz se convierte (a través de un puntero) a bool
, dando como resultado true
ya que su dirección no es nula. Esto sale como 1
menos que use el manipulador std::boolalpha
.
No puede usar la sobrecarga para const char *
que generaría la cadena, o la de const void *
que generaría el valor del puntero, ya que esas conversiones requerirán la eliminación del calificador volatile
. Las conversiones de puntero implícitas pueden agregar calificadores, pero no pueden quitarlos.
Para generar la cadena, deberías desechar el calificador:
std::cout << const_cast<const char*>(test) << "/n";
pero tenga en cuenta que esto da un comportamiento indefinido ya que se accederá a la matriz como si no fuera volátil.
printf
es una función variadica de la vieja escuela, que no ofrece ningún tipo de seguridad. El especificador %s
hace que interprete el argumento como const char *
, sea lo que sea.
Respuesta encontrada here por una cantidad mínima de búsqueda web:
Respuesta corta:
cout
es interpretar el objeto como unbool
debido al calificadorvolatile
. Es un capricho de sobrecarga para el operador<<
.Respuesta larga: un puntero volátil no se puede convertir en un puntero no volátil sin una conversión explícita, por lo que no se puede usar la sobrecarga
char*
nivoid*
cuando se llama al operador<<
. No hay una sobrecarga calificada volátil, y la coincidencia más cercana es la sobrecargabool
, por lo que su matriz se interpreta como un valor booleano en lugar de una dirección o una cadena.Puedes arreglarlo de varias maneras, pero probablemente lo que querías es una conversión explícita:
std::cout<< (char*)test <<std::endl;
(Personalmente lo echaría a const char*
.)
std::basic_ostream::operator<< solo tiene una sobrecarga para const char*
o const void*
que no coincide en este caso, ya que no puede descartar el calificador volátil sin una conversión, esto se trata en el borrador de la sección estándar de C ++ 4.4
Conversiones de calificación que dice:
Un prvalor de tipo "puntero a cv1 T" se puede convertir a un prvalor de tipo "puntero a cv2 T" si "cv2 T" es más cv-calificado que "cv1 T".
por lo tanto, está utilizando la versión bool
y, como no es un valor nullptr
el resultado es true
.
Si elimina el calificador volátil de la test
esto proporcionará el resultado que espera. Varias respuestas sugieren utilizar un const_cast
para eliminar los calificadores volátiles, pero este es un comportamiento indefinido. Podemos verlo yendo a la sección 7.1.6.1
El párrafo 6 de los calificadores cv que dice:
Si se intenta referirse a un objeto definido con un tipo calificado volátil a través del uso de un valor de gl, con un tipo calificado no volátil, el comportamiento del programa no está definido.
En este caso, const_cast produce un valor predeterminado, pero al eliminar la referencia a ese puntero, se obtiene un valor que invoca un comportamiento indefinido.