hola tanto tiempo

81 views
Skip to first unread message

Daniel Gutson

unread,
Feb 23, 2012, 1:54:21 PM2/23/12
to cppba
char c = f();

if ( c == 0xff )
{
    ...
}
else
{
    ...
}

   qué onda?


--
Who’s got the sweetest disposition?
One guess, that’s who?
Who’d never, ever start an argument?
Who never shows a bit of temperament?
Who's never wrong but always right?
Who'd never dream of starting a fight?
Who get stuck with all the bad luck?

Daniel Gutson

unread,
Feb 23, 2012, 1:55:04 PM2/23/12
to cppba
pd: a ver si contestan nuevos, en vez de los sospechosos de siempre

Fernando Cacciola

unread,
Feb 23, 2012, 1:59:12 PM2/23/12
to cp...@googlegroups.com
Uhhh que malo que sos....

Esto es MUUUY sutil

On Thu, Feb 23, 2012 at 3:54 PM, Daniel Gutson <daniel...@gmail.com> wrote:

> --
> ¿Eres miembro de "CyC++ Buenos Aires" verdad? Si no lo eres, has recibido
> este mesaje por error.
> En caso de duda visita "http://groups.google.com/group/cppba"

--
Fernando Cacciola
SciSoft Consulting, Founder
http://www.scisoft-consulting.com

Daniel Gutson

unread,
Feb 23, 2012, 2:01:20 PM2/23/12
to cp...@googlegroups.com
y un bug real que le ocurrió a un amigo y me preguntó hoy porque no entendía qué pasaba :)

Ramiro del Corro

unread,
Feb 23, 2012, 2:09:44 PM2/23/12
to cp...@googlegroups.com
Puede que sea por si char es signed, 0xFF deberia ser -1, pero como 0xFF es int, lo usa como 255 y nunca entraria al if? Muy frio?

Daniel Gutson

unread,
Feb 23, 2012, 2:29:45 PM2/23/12
to cp...@googlegroups.com
 

Daniel Gutson

unread,
Feb 23, 2012, 2:30:58 PM2/23/12
to cp...@googlegroups.com
Ahora bien, cómo lo arreglarían?

Ramiro del Corro

unread,
Feb 23, 2012, 2:39:35 PM2/23/12
to cp...@googlegroups.com
usando unsigned char o (char)0xFF?

Daniel Gutson

unread,
Feb 23, 2012, 2:41:05 PM2/23/12
to cp...@googlegroups.com
Ahí no la clavaste en el ángulo.

Alguien más?

Ramiro del Corro

unread,
Feb 23, 2012, 3:03:20 PM2/23/12
to cp...@googlegroups.com

Agrego otra de este estilo que me paso:

char a = 0xFF (esto salia de un ifstream binario)
int b = a;

Mi idea era q b == 0xFF :(

Daniel Gutson

unread,
Feb 23, 2012, 3:05:52 PM2/23/12
to cp...@googlegroups.com
es lo mismo castear de cualquier cosa a cualquier cosa? (en términos de dirección)

Si T1 y T2 son dos tipos de datos, siempre va a ser lo mismo para estos propósitos castear en cualquier dirección?

Doc

unread,
Feb 23, 2012, 8:50:35 PM2/23/12
to CyC++ Buenos Aires
Yo creo que no.
Tomando "estos propósitos" como comparar por igualdad, si tenés:
float a = 1.5f;
int b = 1;
if(b == int(a))
{
...
}

entra en el if,
mientras que con:
if(float(b) == a)
{
....
}

no entra en el if.


Volviendo a la pregunta original, yo usaría una mascara y compararía
por igualdad:

if((c&0xff) == 0xff)




On Feb 23, 5:05 pm, Daniel Gutson <danielgut...@gmail.com> wrote:
> es lo mismo castear de cualquier cosa a cualquier cosa? (en términos de
> dirección)
>
> Si T1 y T2 son dos tipos de datos, siempre va a ser lo mismo para estos
> propósitos castear en cualquier dirección?
>
> On Thu, Feb 23, 2012 at 5:03 PM, Ramiro del Corro <
>
>
>
>
>
>
>
>
>
> ramiro.del.co...@gmail.com> wrote:
> > Agrego otra de este estilo que me paso:
>
> > char a = 0xFF (esto salia de un ifstream binario)
> > int b = a;
>
> > Mi idea era q b == 0xFF :(
> > On Feb 23, 2012 4:41 PM, "Daniel Gutson" <danielgut...@gmail.com> wrote:
>
> >> Ahí no la clavaste en el ángulo.
>
> >> Alguien más?
>
> >> On Thu, Feb 23, 2012 at 4:39 PM, Ramiro del Corro <
> >> ramiro.del.co...@gmail.com> wrote:
>
> >>> usando unsigned char o (char)0xFF?
>
> >>> On Thu, Feb 23, 2012 at 11:30 AM, Daniel Gutson <danielgut...@gmail.com>wrote:
>
> >>>> Ahora bien, cómo lo arreglarían?
>

Fernando Cacciola

unread,
Feb 23, 2012, 8:53:01 PM2/23/12
to cp...@googlegroups.com
> if((c&0xff) == 0xff)
>
Y eso qué da si c, de tipo char, vale -1 ?

Eduardo

unread,
Feb 23, 2012, 9:05:35 PM2/23/12
to CyC++ Buenos Aires
Permiso caballeros. Jamás escribo pero siempre los leo.

En problemas de ese estilo siempre me saca del agua el código
assembler generado.

En este caso es:

; if ( c == 0xff )
;
?live1@32: ; EAX = c
movsx eax,al
cmp eax,255
jne short @2

Donde se vé por qué vamos muertos. Al char lo pasa a 32bit extendiendo
el signo y después compara con 255.


O bien c se define como unsigned char o hacemos if ( c == -1 )

Fernando Cacciola

unread,
Feb 23, 2012, 9:31:30 PM2/23/12
to cp...@googlegroups.com
Hola Eduardo,

[esto tiene tela para cortar]

Vayamos por parte:

>
> o hacemos if ( c == -1 )
>

Usar -1 en lugar de 0xFF es decididamente un paso adelante, pero, no
es solo por lo que vos empiricamente viste que pasa:

Veamos:

(1)

char c = -1 ;

char magic = 0xFF ;

if ( c == magic )

Ya no hay ninguna conversión implícita haciendo lio, pero, anda?

NO lo prueben porque van a llegar a la conclusión equivocada, salvo
que tengan un máquina poco convensional.

Por otro lado, tu version es equivalente a esto:

(2)

char c = -1 ;

if ( (int)(c) == -1 )

Seguro que anda?

De nuevo no lo prueben, salvo que el compilador perfectamente legal lo
hayan hecho a proposito para demotrar que....ç


>
> O bien c se define como unsigned char
>

Cuando esten resultos los dos puntos anteriores vuelvo sobre esto.

Carlos Cattaneo

unread,
Feb 23, 2012, 9:39:50 PM2/23/12
to cp...@googlegroups.com
Es corecto que haga eso el compilador haga eso ya que la comparación la tiene que hacer entre enteros con signo.
El literal 0xff es un entero con signo y por lo tanto tiene que primero promover a c a un entero con signo y luego comparar.
 
Para solucionar esta tema de manera portable debemos hacer que la constante sea un literal de tipo char, es decir
\xhh
 
con lo que la línea de código quedaría:
 
if ( c == \xff )
 
Una aclaración adicional:
 
char, unsigned char y signed char son 3 tipos diferentes. Durante la conversión de char a int el compilador es libre de elegir si lo considera con signo o no, por lo tanto comparar contra -1 no es portable.
 
Saludos
Carlos Cattaneo
 

Fernando Cacciola

unread,
Feb 23, 2012, 9:51:34 PM2/23/12
to cp...@googlegroups.com
Hola Carlos tanto tiempo!

Dije que esto daba para rato :)


> con lo que la línea de código quedaría:
>
> if ( c == \xff )
>

Todavía quedan 'huecos' por resolver aún en esta versión.

Fijate la devolución a Eduardo.

> Una aclaración adicional:
>
> char, unsigned char y signed char son 3 tipos diferentes. Durante
> la conversión de char a int el compilador es libre de elegir si lo considera
> con signo o no, por lo tanto comparar contra -1 no es portable.
>

Ahí nos vamos acercando.
Efectivamente el -1 no es portable si convertimos el char a int.

Por otro lado, técnicamente, la dicotomía existe aún mas allá de la
conversión a entero.
Es decir:

char c0 = -1 ;
unsigned char c1 = -1 ;
signed chat c2 = -1 ;

if ( c0 == c1 )
if ( c0 == c2 ) ;

Alguno de los if() da true? Cuál?

Eduardo

unread,
Feb 23, 2012, 10:24:37 PM2/23/12
to CyC++ Buenos Aires
On Feb 23, 11:31 pm, Fernando Cacciola <fernando.cacci...@gmail.com>
wrote:
> Por otro lado, tu version es equivalente a esto:
>
> (2)
>
>  char c = -1 ;
>
>  if ( (int)(c) == -1 )
>
> Seguro que anda?
>

Hola Fernando!

Eso anda según mi entender (y mi método de control :-) ), aunque
debido al (int) tiene que hacer una conversión antes de comparar. De
la otra forma compara directamente dos registros de 8bits.

Eduardo

unread,
Feb 23, 2012, 10:30:08 PM2/23/12
to CyC++ Buenos Aires


On Feb 23, 11:51 pm, Fernando Cacciola <fernando.cacci...@gmail.com>
wrote:
>
> char c0 = -1 ;
> unsigned  char c1 = -1 ;
> signed chat c2 = -1 ;
>
> if ( c0 == c1 )
> if ( c0 == c2 ) ;
>
> Alguno de los if() da true? Cuál?
>

Dependerá de cómo el compilador asigna por defecto a char, si signed
o unsigned.








Fernando Cacciola

unread,
Feb 23, 2012, 10:31:38 PM2/23/12
to cp...@googlegroups.com
>
> Hola Fernando!
>
> Eso anda según mi entender (y mi método de control :-) ),

OK, una pista entonces.

NO lo prueben porque les va a andar.. y sin embargo eso no quiere decir nada :)

P.S.:

Otra pista... C y C++, a diferencia de muchos otros lenguajes, está
pensado para permitir al programador escribir un fuente y correr el
programa resultante en cualquier cosa capaz de ser programada, y
entonces, esta DEFINIDO de un modo que haga eso posible.
Decimos entonces que la *especificación* del lenguaje (según un
determinado estandard) dice que las cosas son de uno y/o otro modo, y
es eso lo que debe ser considerado para decidir si el programa que
escribimos hace *garantizadamente* esto o aquello.

Saludos

Fernando Cacciola

unread,
Feb 23, 2012, 10:33:15 PM2/23/12
to cp...@googlegroups.com
> Dependerá de cómo el compilador asigna por defecto  a char,  si signed
> o unsigned.
>

ESO.

Entonces?

si char c = -1 ;

(int)(c) da o no da -1??

Eduardo

unread,
Feb 23, 2012, 10:47:04 PM2/23/12
to CyC++ Buenos Aires


On Feb 24, 12:33 am, Fernando Cacciola <fernando.cacci...@gmail.com>
wrote:
> > Dependerá de cómo el compilador asigna por defecto  a char,  si signed
> > o unsigned.
>
> ESO.
>
> Entonces?
>
> si char  c = -1 ;
>
> (int)(c) da o no da -1??
>

Ja ja! Lo que pasa es que recién cuando contesté esto caí en lo que
apuntabas.

En mi pequeño mundo x86 son los chars e ints signados por defecto,
pero en el mundo de los microcontroladores son unsigned por defecto.




Fernando Cacciola

unread,
Feb 23, 2012, 11:07:06 PM2/23/12
to cp...@googlegroups.com
>
> En mi pequeño mundo x86 son los chars e ints signados por defecto,
> pero en el mundo de los microcontroladores son unsigned por defecto.
>

Ojo que complemento del x86 no es solo el mundo de los microcontroladores (*)

Por otro lado:

Lo que debemos saber es que:

un char puede, "internamente", ser un signed char o un unsigned char,
según lo defina el compilador.

(*)

Miren este listado de "arquitecturas" *que son todavía suficientemente
relevantes:

http://svn.boost.org/svn/boost/sandbox/predef/libs/predef/doc/html/predef/reference.html#predef.reference.boost_architecture_architecture_


P.S.: Todavía falta el tema del (signed char)(-1) vs 0xFF

Doc

unread,
Feb 23, 2012, 11:46:23 PM2/23/12
to CyC++ Buenos Aires
Impresionante todo lo que se aprende.

Preguntas:
¿cuál es la razón o ventaja que tiene permitir que char pueda ser
interpretado como signed o como unsigned?
¿Por qué no exigir que el programador especifique el signo?
¿pasa lo mismo con integer, signed integer y unsigned integer?


Siguiendo con este razonamiento creería que (signed char)(-1) == 0xFF
sería falso, ya que 0xFF es un entero positivo (¿las constantes por
default son enteros con signo, no?) y se castea el (signed char) -1 a
signed integer, manteniendo el valor (-1).


On Feb 24, 1:07 am, Fernando Cacciola <fernando.cacci...@gmail.com>
wrote:
> > En mi pequeño mundo x86 son los chars e ints signados por defecto,
> > pero en el mundo de los microcontroladores son unsigned por defecto.
>
> Ojo que complemento del x86 no es solo el mundo de los microcontroladores (*)
>
> Por otro lado:
>
> Lo que debemos saber es que:
>
> un char puede, "internamente", ser un signed char o un unsigned char,
> según lo defina el compilador.
>
> (*)
>
> Miren este listado de "arquitecturas" *que son todavía suficientemente
> relevantes:
>
> http://svn.boost.org/svn/boost/sandbox/predef/libs/predef/doc/html/pr...

Fernando Cacciola

unread,
Feb 24, 2012, 7:00:45 AM2/24/12
to cp...@googlegroups.com
> Preguntas:
> ¿cuál es la razón o ventaja que tiene permitir que char pueda ser
> interpretado como signed o como unsigned?

Buena pregunta:

signed/unsigned char son tipos enteros que sirven para representar
números enteros con o sin signo, mientras que char a secas, aunque
puede ser usado del mismo modo (tal como ocurre en la práctica),
existe en sí mismo como el tipo de dato que representa de un byte.

Es decir, un bloque de memoria, es decir el *storage* que le
corresponde a un *objeto* (o lvalue en C), está definido como una
secuencia de chars (y no como una secuencia de signed char o unsigned
char). Resulta entonces que necesitamos del tipo char como un tipo
diferente a signed/unsigned char para referir a bloques de memoria.

Ahora bien, si tenemos que tener esos tres tipos, y char tiene que
ser el que corresponde a un byte, porqué especificar si tiene que ser
con o sin signo en lugar de dejar a la implementación (o sea el
compilador) decidirlo?

Por otro lado, uno podria pensar que char podría no tener nada que ver
con signed or unsigned char y tener en cambio su propia definicion
independiente (que de todos modos no especificaria si puede o no
representar números negativos (*) para no forzar al compilador
innecesariamete)
.Net por ejemplo distingue explicitamente uno de otros:

http://msdn.microsoft.com/en-us/magazine/bb984984.aspx

Aunque hace explícito el tema del signo: byte es unsigned mientras que
sbyte es signed (en mi opninión esto es un error, pero...)

> ¿Por qué no exigir que el programador especifique el signo?

Acá está el quiz de la cuestón:

el verdadero propósito de char es,k o debería ser en mi opinión,
representar un byte. Y la arquitectura define el byte como se le da la
gana, incluso en cuanto a la cantidad de bits (sizeof(char)==8 no es
siempre cierto!)

Ahora, si el programador quiere representar números pequeños, debe, o
puede al menos, usar signed char or unsigned char, con lo cual está
especificando el signo como decis.

Que en la práctica se abuse de char para, por ejemplo, representar
caracteres en un archivo o string, es posiblemente un accidente
cultural (tal vez en K&R no había todavía signed char/unsigned char?
sería interesante investigar esto)

> ¿pasa lo mismo con integer, signed integer y unsigned integer?
>

NO

Para cualquier otro tipo de dato entero, signed está implicito:

typeof(signed int)==typeof(int), lo mismo para short, long, etc...

>
> Siguiendo con este razonamiento creería que (signed char)(-1) == 0xFF
> sería falso, ya que 0xFF es un entero positivo

> (¿las constantes por
> default son enteros con signo, no?)

Los *literales* (no constantes) son de un determinado tipo que depende
del la forma del literal, y sí, para el caso de "solo un número" (mas
allá de que sea decimal o hexdecimal), el tipo es signed int, que es
lo mismo que int.

1u por otro lado es un unsgined int, etc..

> y se castea el (signed char) -1 a
> signed integer, manteniendo el valor (-1).
>

Hmm, en realidad me equivoqué y quise preguntar por:

(unsigned char)(-1) == 0xFF

Eso es o no cierto?

[todavía hay un tema más que del cual no se habló para nada todavía]


Saludos

Carlos Cattaneo

unread,
Feb 24, 2012, 8:53:05 AM2/24/12
to cp...@googlegroups.com
En las líneas de código
 
if ((unsigned char)(-1) == 0xFF)
 
o
 
if ((unsigned char)(-1) == 0xFF)
 
La constante 0xFF es un entero con el número 255. Por eso a pesar del los casts explícitos el compilador vuelve a promover a int al primer operando de la comparación. Es decir, la instrucción de comparación generada por el compilador debería ser una instrucción de comparación del tipo entero que tiene como tamaño al "nativo" de la plataforma.
 
Por eso, si lo que quiero es usar char como una forma de guardar números pequeños que ocupen menos espacio, luego es un laburo chino escribir el resto del código correctamente. No es una práctica recomendable.
 
Lo que sí puede suceder es que necesite manejar la memoria en el nivel del byte o del caracter como por ejemplo las funciones manejo de strings de C en la biblioteca standard.
 
Si llegara a tener que comparar una variable de tipo char contra una constante, en mi opinión debo usar constantes de tipo char que por supuesto existen en el lenguaje.
 
Una segunda aclaración con respecto al tema signed vs unsigned (tanto char como int como long)
 
La diferencia entre ambos tipos sólo se pone de manifiesto durante la "impresión" por ejemplo vía printf o en la comparación por menor, menor o igual, mayor o mayor o igual. De hecho los procesadores de Intel tienen por cada una de las comparaciones nombradas, una para signed y otra para unsigned. El resto de las operaciones aritméticas y de comparación por igual o por distinto SON LAS MISMAS porque operan sobre la representación de bits.
 
Por ejemplo, supongamos que estamos en una plataforma de 32 bits.
 
signed int a = -1;
 
unsigned int b = 0xffffffff;
 
tienen la misma representación de bits y es todo lo que le importa al procesador a la hora de comparar por igual o distinto, o a la hora de sumar, restar, multiplicar, etc.
 
Y esto funciona gracias a como se comporta la aritmética de complemento 2.
 
Por ejemplo;
 
signed int c = 10;
unsigned int d = 10;
 
printf("d", c + a);
printf("d", d + b);
 
En ambos casos se imprime 9. En el segundo caso tiene que sumar (2^32-1)+10 = 2^32+9 y termina dando 9 porque el bit más significativo se pierde por overflow.
 
En cambio si tengo:
 
signed int c = 0;
unsigned int d = 0;
 
printf("d", c + a);
printf("d", d + b);
 
En el primer caso imprime -1 y en el segundo 2^32-1, aunque la representación de bits del segundo argumento de printf sea idéntica.
 
 
Si comparo
 
if (c > a)
da true
 
if (d > b)
da false
 
En cambio si comparo
 
if (a == b)
 
Podría dar true si el compilador generara una instrucción de comparación de 32 bits.
 
 
Espero haber sido claro.
 
 
Saludos,
Carlos Cattaneo
 
 
 
 
 
 
 
 
 
 

Fernando Cacciola

unread,
Feb 24, 2012, 9:19:50 AM2/24/12
to cp...@googlegroups.com
>
> Y esto funciona gracias a como se comporta la aritmética de complemento 2.
>

Y justamente a esto iba mi pregunta. Pero esta vez me voy a responder.

En C y C++ los números enteros no necesariamente tienen que usar
complemento a 2. Eso lo define el compilador de acuerdo a la
arquitectura que estamos usando.

Así, -1 puede ser 0xFF..FE (complemeto a 1) en lugar de 0xFF..FF

De hecho, hasta puede ser signo+magnitud (o sea con un bit de signo)

Daniel Gutson

unread,
Feb 24, 2012, 11:35:52 AM2/24/12
to cp...@googlegroups.com
Increíble cómo se desarrolló esto mientras no estuve, y qué bueno q Fernando tomó la posta :)

Poco me queda agregar a mí, salvo, y lejos de cerrar el tema, ir a los consejos que quiero dejar.

Quiero antes redundar en la respuesta a Rodrigo (si bien Fernando ya aclaró q es una cuestión "cultural").
"char" no está intended para ser operado aritméticamente, como sí lo son signed char y unsigned char. Que alguien se meta con el signo del char es un error, si quiere especificarlo como pregunta Rodrigo, para eso que use (un)signed char que justamente esa es la manera de especificarlo.
Si yo uso "char" a secas es que estoy diciendo "me interesa manipular los bytes de la memoria, no pasarlos por la ALU". Qué (operaciones) me puede interesar hacer con un char? Copiar memoria ciegamente, utilizarlo para comunicarme con humanos ("printf") u otras computadoras, pero no para hacer cuentas (incluyendo comparaciones).

Otra cosa que quiero aclarar: los tipos de datos tienen información. Un atributo de un tipo de dato es su tamaño, pero no es el único; el atributo fundamental es "cuánta información provee un tipo de dato".
Por supuesto que si sizeof(T1) > sizeof(T2) entonces cant_info(T1) > cant_info(T2).
Pero si sizeof(T1) == sizeof(T2) aún puede ocurrir que  cant_info(T1) > cant_info(T2).
Así las cosas, se dice "promotion" cuando convierto (yo o el compilador) de un tipo de dato con menor cantidad de información que el de destino, mientras que "demotion" es al revés. Un caso particular de demotion es truncar flotante a entero.
Ahora bien, el consejo es: usen SIEMPRE promotions, ya que cuando ocurren demotions se exponen al error 
(o porque es algo implementación-dependiente, o sutileza-dependiente).

Finalmente, el mi último consejo de este thread: CUIDADO con los literales.
Los literales tienen tipo de dato; hay muchos tipos de literales, con su tipo de dato asociado y la cantidad de información de ese tipo de dato.
0xff es ENTERO CON SIGNO.
0xffu es ENTERO SIN SIGNO.
\xff es? :)
2.0 es DOUBLE
2.0f es FLOAT (cant_info(float) < cant_info(double), por lo tanto 
    float f = 2.0
va a ocurrir un demotion o un promotion? Es "safe" hacer eso?

Recuerden que están haciendo casts implícitos tanto en asignaciones como en comparaciones. Por default, un compilador siempre hará promotion, pero no está bueno dejárselo hacer, está bueno que especifiquen cuál es su intención para no ser sutileza-dependiente, y ser explícito a otros globos oculares menos cultos o más escépticos.


2012/2/24 Fernando Cacciola <fernando...@gmail.com>
--
¿Eres miembro de "CyC++ Buenos Aires" verdad? Si no lo eres, has recibido este mesaje por error.
En caso de duda visita "http://groups.google.com/group/cppba"
Reply all
Reply to author
Forward
0 new messages