upper strtoupper mayus lower change c++

strtoupper - toupper() c++



¿Necesito lanzar a char sin firmar antes de llamar a toupper? (5)

Hace un tiempo, alguien con una gran reputación aquí en StackOverflow escribió en un comentario que es necesario lanzar un argumento de char a unsigned char antes de llamar a std::toupper (y funciones similares).

Por otro lado, Bjarne Stroustrup no menciona la necesidad de hacerlo en C ++ - Lenguaje de programación. Él solo usa toupper como

string name = "Niels Stroustrup"; void m3() { string s = name.substr(6,10); // s = "Stroustr up" name.replace(0,5,"nicholas"); // name becomes "nicholas Stroustrup" name[0] = toupper(name[0]); // name becomes "Nicholas Stroustrup" }

(Citado de dicho libro, 4ª edición).

La referencia dice que la entrada debe ser representable como unsigned char . Para mí, esto suena como válido para cada char ya que char y unsigned char tienen el mismo tamaño.

Entonces, ¿este lanzamiento es innecesario o Stroustrup fue descuidado?

Editar: El manual de libstdc ++ menciona que el carácter de entrada debe ser del conjunto de caracteres fuente básico , pero no se emite. Supongo que esto está cubierto por la respuesta de @Keith Thompson, todos tienen una representación positiva como signed char y unsigned char .


En C, toupper (y muchas otras funciones) toman int s aunque esperas que tomen char . Además, char está firmado en algunas plataformas y sin firmar en otras.

El consejo de enviar a unsigned char antes de llamar a toupper es correcto para C. No creo que sea necesario en C ++, siempre que lo pases por un int que esté dentro del rango. No puedo encontrar nada específico sobre si es necesario en C ++.

Si desea eludir el problema, use el toupper definido en <locale> . Es una plantilla y toma cualquier tipo de carácter aceptable. También debe pasarlo por std::locale . Si no tiene idea de qué configuración regional elegir, use std::locale("") , que se supone que es la configuración regional preferida del usuario:

#include <algorithm> #include <iostream> #include <iterator> #include <locale> #include <string> int main() { std::string name("Bjarne Stroustrup"); std::string uppercase; std::locale loc(""); std::transform(name.begin(), name.end(), std::back_inserter(uppercase), [&loc](char c) { return std::toupper(c, loc); }); std::cout << name << ''/n'' << uppercase << ''/n''; return 0; }


En lugar de lanzar el argumento como char sin signo, puede lanzar la función. Deberá incluir un encabezado funcional . Aquí hay un código de muestra:

#include <string> #include <algorithm> #include <functional> #include <locale> #include <iostream> int main() { typedef unsigned char BYTE; // just in case std::string name("Daniel Brühl"); // used this name for its non-ascii character! std::transform(name.begin(), name.end(), name.begin(), (std::function<int(BYTE)>)::toupper); std::cout << "uppercase name: " << name << ''/n''; return 0; }

El resultado es:

uppercase name: DANIEL BRüHL

Como era de esperar, toupper no tiene ningún efecto sobre los personajes no ascii. Pero este casting es beneficioso para evitar comportamientos inesperados.


La referencia se refiere al valor que se puede representar como un unsigned char , no a un unsigned char . Es decir, el comportamiento no está definido si el valor real no está entre 0 y UCHAR_MAX (típicamente 255). (O EOF , que es básicamente la razón por la que toma un int lugar de un char .)


Lamentablemente Stroustrup fue descuidado :-(
Y sí, los códigos de letras latinas deberían ser no negativos (y no se requiere molde) ...
Algunas implementaciones funcionan correctamente sin conversión a char sin firmar ...
Por alguna experiencia, puede costar varias horas encontrar la causa de segfault de un toupeper de este tipo (cuando se sabe que hay una segfault) ...
Y también hay isupper, islower, etc.


Sí, el argumento para toupper debe convertirse en unsigned char para evitar el riesgo de un comportamiento indefinido.

Los tipos char , signed char y unsigned char son tres tipos distintos. char tiene el mismo rango y representación que el signed char o el unsigned char . (El char normal está muy comúnmente firmado y puede representar valores en el rango -128 .. + 127).

La función toupper toma un argumento int y devuelve un resultado int . Citando el estándar C, sección 7.4, párrafo 1:

En todos los casos, el argumento es un int , cuyo valor debe ser representable como un unsigned char o debe ser igual al valor de la macro EOF . Si el argumento tiene otro valor, el comportamiento no está definido.

(C ++ incorpora la mayor parte de la biblioteca estándar C, y difiere su definición al estándar C).

El operador de indexación [] en std::string devuelve un valor de char . Si el char simple es un tipo firmado, y si el valor devuelto por el name[0] pasa a ser negativo, entonces la expresión

toupper(name[0])

tiene un comportamiento indefinido

El lenguaje garantiza que, incluso si se firma un char simple, todos los miembros del conjunto de caracteres básicos tienen valores no negativos, por lo que, dada la inicialización

string name = "Niels Stroustrup";

el programa no se arriesga a un comportamiento indefinido. Pero sí, en general, un valor de char pasado a toupper (o a cualquiera de las funciones declaradas en <cctype> / <ctype.h> necesita convertirse en unsigned char , de modo que la conversión implícita a int no arroje un resultado negativo valorar y causar un comportamiento indefinido.

Las funciones <ctype.h> se implementan comúnmente utilizando una tabla de búsqueda. Algo como:

// assume plain char is signed char c = -2; c = toupper(c); // undefined behavior

puede indexar fuera de los límites de esa tabla.

Tenga en cuenta que la conversión a unsigned :

char c = -2; c = toupper((unsigned)c); // undefined behavior

no evita el problema Si int es de 32 bits, convertir el valor de char -2 a unsigned produce 4294967294 . Esto se convierte implícitamente en int (el tipo de parámetro), que probablemente rinde -2 .

toupper puede implementarse para que se comporte de manera sensata con los valores negativos (aceptando todos los valores desde CHAR_MIN hasta UCHAR_MAX ), pero no es obligatorio. Además, las funciones en <ctype.h> son necesarias para aceptar un argumento con el valor EOF , que generalmente es -1 .

El estándar C ++ realiza ajustes en algunas funciones de biblioteca estándar de C. Por ejemplo, strchr y varias otras funciones son reemplazadas por versiones sobrecargadas que imponen la corrección const . No hay tales ajustes para las funciones declaradas en <cctype> .