Mientras estaba armando una función en mayúsculas en C++, noté que no recibí el resultado esperado en C.
Función C++
#include <iostream>
#include <cctype>
#include <cstdio>
void strupp(char* beg)
{
while (*beg++ = std::toupper(*beg));
}
int main(int charc, char* argv[])
{
char a[] = "foobar";
strupp(a);
printf("%s\n", a);
return 0;
}
Salida como se esperaba:
FOOBAR
función C
#include <ctype.h>
#include <stdio.h>
#include <string.h>
void strupp(char* beg)
{
while (*beg++ = toupper(*beg));
}
int main(int charc, char* argv[])
{
char a[] = "foobar";
strupp(a);
printf("%s\n", a);
return 0;
}
La salida es el resultado esperado con el primer carácter que falta
OOBAR
¿Alguien sabe por qué el resultado se trunca al compilar en C?
NathanOliver
El problema es que no hay un punto de secuencia en
while (*beg++ = toupper(*beg));
Así que tenemos un comportamiento indefinido. Lo que el compilador está haciendo en este caso es evaluar beg++
antes de toupper(*beg)
En C donde en C++ lo está haciendo al revés.
-
¿Significa esto que el clásico c-string copia una sola línea?
while(*s++ = *t++) ;
tiene un comportamiento indefinido?– marca h
13 de octubre de 2015 a las 1:20
-
@markh No, ya que son dos variables diferentes. Esto es sinónimo de
while (*s++ = *s++)
– NathanOliver
13 de octubre de 2015 a las 1:40
-
@SteveJessop En realidad,
while(*s++ = *t++);
tiene un comportamiento definido incluso sis == t
. La razónstrcpy
no está definido con regiones superpuestas es questrcpy
no se implementa necesariamente conwhile(*s++ = *t++);
.– usuario253751
13 de octubre de 2015 a las 3:11
-
@immibis: punto justo, de acuerdo, está definido. Sin embargo, incluso si
strcpy
se implementa con ese ciclo, todavía tiene un comportamiento indefinido para una “dirección” de superposición. Si el destino es mayor que el origen y se superponen, entonces el nul de terminación se sobrescribe antes de que se lea y, finalmente, ¡el búfer se desborda! La razón por la que la superposición está prohibida en ambas “direcciones” es por posibles otras implementaciones.–Steve Jessop
13 de octubre de 2015 a las 3:16
R Sahú
while (*beg++ = std::toupper(*beg));
conduce a un comportamiento indefinido.
Ya sea *beg++
se secuencia antes o después std::toupper(*beg)
no está especificado.
La solución simple es usar:
while (*beg = std::toupper(*beg))
++beg;
La línea
while (*beg++ = toupper(*beg));
contiene un efecto secundario en una entidad que se usa dos veces. No puede saber si beg++ se ejecuta o no antes o después de *beg (dentro del toupper). Tiene suerte de que ambas implementaciones muestren ambos comportamientos, ya que estoy bastante seguro de que es lo mismo para C++. (Sin embargo, hubo algunos cambios en las reglas para c ++ 11, de los cuales no estoy seguro; aún así, es un mal estilo).
Simplemente mueva el beg ++ fuera de la condición:
while (*beg = toupper(*beg)) beg++;
vishal
con respecto a la respuesta anterior, la ‘f’ nunca se pasa dentro de la función, debe intentar usar esto:
while ((*beg = (char) toupper(*beg))) beg++;
Y si realmente quisieras hacer esto en
C++
:std::transform(a, a + strlen(a), a, std::toupper);
– Paul McKenzie
12/10/2015 a las 16:40
¿Puede explicar por qué esperaba que esto convirtiera una cadena a mayúsculas? Específicamente, ¿por qué esperabas que el lado derecho de la
=
para ser evaluado antes de la izquierda?–David Schwartz
12/10/2015 a las 16:41
Estoy agradecido con todas las personas que dieron su opinión y por la valiosa información proporcionada.
– Alex Koukoulas
12/10/2015 a las 16:46
@Schullz Creo firmemente que aprender de tus errores es la forma más eficiente de no volver a cometer el mismo error. Por lo tanto, como este problema surgió únicamente de la experimentación y no en un entorno de proyecto de equipo, no creo que haya sido un error escribir este fragmento de código para empezar.
– Alex Koukoulas
12/10/2015 a las 23:04
@MillieSmith En este caso, ¿importa el orden de qué elemento se hará en mayúsculas? De todos modos, la mayoría, si no todos, los enfoques clásicos de C ++ para mutar una cadena usan
std::transform
.– Paul McKenzie
13 de octubre de 2015 a las 10:09