Autor Tema: Proyecto de Curso (Comentarios): Programación en C (2013, por Argentinator)

0 Usuarios y 1 Visitante están viendo este tema.

06 Enero, 2013, 04:08 pm
Respuesta #60

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Citar
¿Cómo entiende "0u" la maquina, qué es para ella la u, un indicador de estado de algún bit de cierto byte relacionada con alguna dirección importante de memoria; una orden...? Quizá lo supe, pero si lo supe no me acuerdo; ¿ves?, es lo que me pasa. 

Eso lo expliqué en la teoría de las constantes de tipo entero: http://rinconmatematico.com/foros/index.php?topic=64835.msg260467#msg260467

Cuando se escribe un número entero seguido de u: 3449u,
el lenguaje C lo interpreta matemáticamente como lo que se ve ahí: el número 3449.
Pero internamente considera que el tipo de datos al que pertenece ese número es un unsigned int. (Un entero sin signo).

Acá el inconveniente es que hay muchos tipos de datos diferentes, pero que tienen significados muy parecidos, e incluso trabajan juntos, se mezclan, y hasta se convierten automáticamente unos en otros, según se le antoje al compilador.

Eso es muy complicado de entender en todo detalle.  >:(

Hice el esfuerzo de explicar, al menos, qué pasa con las constantes.

La constante 3449 matemáticamente es la misma para C que 3449u.
Pero el 3449 lo considera, automáticamente, como un dato de tipo signed int.
Mientras que 3449u es un unsigned int.

Hasta ahí sólo hay una asignación de "tipos de datos" que es interna, y no tiene por qué afectarnos.

Pero ahora viene el problema de que tenemos que sacar cuentas con esos datos.
¿Qué pasa si queremos sumar datos que son de distintos tipos?
¿Cómo los toma el compilador?

Si tomo el dato 20 (que es de tipo signed int) y le sumo 20u (que es de tipo unsigned int), ¿qué hace el compilador cuando quiero sumar 20 + 20u?

El resultado matemático en cualquier caso va a ser, por suerte, 40.
Pero lo que no sabemos es de qué tipo es ese 40.
Para especificar eso hay que consultar las reglas de "promoción de tipos".
Sin entrar en demasiados detalles, en este caso el compilador va a transformar el 20 en un 20u, o sea que 20 + 20u se convierte en un primer paso a 20u + 20u, luego se suma, lo cual da 40u (quiero decir, un 40, pero de tipo unsigned int).

El problema está cuando el compilador convierte automáticamente números negativos a tipos "que no tienen signo".
Ahí le cambia no sólo el tipo de datos al número, sino que trastoca el significado que tenían los bits internos del dato guardado en memoria.

El resultado de esto se torna impredecible.
Así, un (-1) convertido a (unsigned int) nos dejará un número positivo sin sentido para nosotros.

A partir de ahí, cualquier serie de cálculos que hagamos, tendrán errores.

Si no nos damos cuenta de que el compilador está haciendo estas conversiones automáticas de tipos, en el aire, y sin avisar, no tendremos control sobre errores imprevistos en ciertos cálculos.
Es un tema peligroso.

________________________________

Citar
cuántos bits, en decimal, tiene un byte

Un byte tiene 8 bits, lo cual permite representar 256 números enteros, que van del 0 al 255 si son sin signo, y de -128 a 127 si son "con" signo.

Es el caso de los tipos unsigned char y signed char, por ejemplo.

06 Enero, 2013, 04:11 pm
Respuesta #61

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
La u es un sufijo, que se puede aplicar a constantes numéricas enteros, para forzar al compilador a que considere ese número como perteneciente a uno de los tipos "unsigned" (sin signo).

Igual esto de la u no hace falta para entender el problema.

Este otro programa creo que es más claro, y tiene la misma dificultad con los tipos de datos y el compilador:


#include <stdio.h>

int main(){
    unsigned int cero = 0;

    printf("(-1 + cero)/2 = %d\n\n",  (-1 + cero) / 2 );

    getchar();
}

Al correr ese programa, muestra como resultado 2 mil millones y pico, que no es lo esperado.

El problema está en que el operador de suma: +
hace una conversión de tipos de datos desastrosa,
al convertir el -1 a un entero sin signo, dejando la representación interna de bits a su suerte.

06 Enero, 2013, 06:06 pm
Respuesta #62

feriva

  • Matemático
  • Mensajes: 9,057
  • País: es
  • Karma: +1/-0
  • Sexo: Masculino
  • No soy matemático, eso es una etiqueta.


El problema está en que el operador de suma: +
hace una conversión de tipos de datos desastrosa,
al convertir el -1 a un entero sin signo, dejando la representación interna de bits a su suerte.


Veámos, voy a intentar interpretarlo a ver si estoy en lo cierto:


#include <stdio.h>

// Incluye una librería con una serie funciones prefijadas entre la las cuales, imagino, está definido el significado de “int”, “ unsigned”, etc.

int main()

// Supongo que quiere decir que en el área local, o zona de la memoria principal donde se guardan las rutinas del programa, todas las variables o constantes que se definan serán entendidas por la máquina como valores enteros.


{
    unsigned int cero = 0;

// Esto no sé del todo cómo entenderlo, parece que define una constante llamada “cero” la cual es definida a su vez como entera, sin signo y de valor 0. Los entresijos del comando unsigned -en cuanto al funcionamiento de la máquina- se me escapa; yo sé que hasta el 127 decimal los entiende positivos , así, el -1 se expresa como 256-1, el -2 como 256-2...  y cuando llega al 127 es positivo; esto depende en binario del séptimo bit, que pasa a valer 0 de 127 para abajo... Dado esto, no sé cómo la hace para considerar un número sin signo, pues el séptimo bit será cero ó 1; creo que nunca lo estudié o nunca leí sobre ello. 

    printf("(-1 + cero)/2 = %d\n\n",  (-1 + cero) / 2 );

// Aquí se imprime un par de números separados por una coma. Creo, por lo que he ido viendo, que la instrucción %d llama a un tipo de variables o cosntantes (alfanuméricas, numéricas enteras, etc., según la letra que va detrás del %); en este caso parece que guarda el resultado  de  (-1 + cero)/2, pero no estoy seguro del todo de cómo funciona, es una instrucción muy nueva para mí que no recuerdo haber manejado mucho; leí que cuando es %c se refiere a variables tipo char o algo así pero poco más. El otro número detrás de la coma no va entre comillas, por tanto no es un valor “alfanumérico” (que digo yo en plan antiguo, no sé si se usa así todavía) con lo que la cuestión puede estar también relacionada con este tema del tipo de variables que resultan incompatibles según las instrucciones

   

De todas formas, no te pares mucho por mí, porque este curso puede estar siendo seguido por gente más al día que yo en estas cosas y que se puede aburrir de ir despacio; yo te sigo como pueda, si me entero, bien, y, si no me entero, ya me iré enterando poco a poco.

Saludos  y gracias.

06 Enero, 2013, 07:18 pm
Respuesta #63

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)

Veámos, voy a intentar interpretarlo a ver si estoy en lo cierto:


#include <stdio.h>

// Incluye una librería con una serie funciones prefijadas entre la las cuales, imagino, está definido el significado de “int”, “ unsigned”, etc.


No.
El significado de "int", "unsigned", etc., viene establecido directamente en el compilador, no en las librerías.

La librería "stdio.h" sólo define funciones de entrada y salida de datos, como la función printf() y la función scanf(). También getchar(), el tipo de datos FILE* para manejar archivos, etc.

Citar
int main()

// Supongo que quiere decir que en el área local, o zona de la memoria principal donde se guardan las rutinas del programa, todas las variables o constantes que se definan serán entendidas por la máquina como valores enteros.

NO.

Lo que rodea al "main" para nosotros es irrelevante.
Ese "int" está ahí porque lo puso PabloN.

Lo único que hace eso es enviar un número con código de error al sistema operativo, una vez que el programa terminó.

Citar
{
    unsigned int cero = 0;

// Esto no sé del todo cómo entenderlo, parece que define una constante llamada “cero” la cual es definida a su vez como entera, sin signo y de valor 0. Los entresijos del comando unsigned -en cuanto al funcionamiento de la máquina- se me escapa; yo sé que hasta el 127 decimal los entiende positivos , así, el -1 se expresa como 256-1, el -2 como 256-2...  y cuando llega al 127 es positivo; esto depende en binario del séptimo bit, que pasa a valer 0 de 127 para abajo... Dado esto, no sé cómo la hace para considerar un número sin signo, pues el séptimo bit será cero ó 1; creo que nunca lo estudié o nunca leí sobre ello. 

Bueno, no te compliques con eso, porque la representación binaria interna de los números no es algo que nos importe del todo.
Te explico por qué. El lenguaje C no es lenguaje de máquina, y entonces la manera en que se representan internamente los datos depende de cada compilador.
No es algo que te puedas aprender, porque no está fijado por las reglas del lenguaje C.

Un programador en C no tiene por qué saber o supone cómo se representan los números (o cualquier dato) internamente.

La declaración:

unsigned int cero = 0;

lo que hace es definir una variable, llamada cero, de tipo unsigned int.
Esto quiere decir que lo que fuere que hayamos guardado en esa variable, siempre se va a interpretar como un número entero positivo (o 0).
Eso quiere decir "sin signo".

____________

No se trata de si el -1 es un número positivo o negativo para el C.
De lo que se trata es de cómo lo interpreta, según el tipo de datos de la variable en que fue almacenado.

No es lo mismo el 0 de un "unsigned int" que el 0 de un "signed int".
Ambos se representan igual internamente, así: 00000000.......
Es muy fácil representar el 0.
Y aunque se representan de la misma forma, son datos de distinto tipo.

La distinción de tipos de datos es una convención "de alto nivel", no es algo que puedas ver en los bits de la máquina, sino que es una convención del lenguaje.

Un ejemplo más práctico quizá te lo muestre mejor.
El caracter '@' se representa en binario internamente: 01000000.
Eso también es el código binario del número decimal 64.

Ambos se escriben en memoria como 01000000, pero el '@' representa un dato de tipo "char", mientras que 64 representa un dato de tipo "int".

¿Cómo sabe el C que son datos de distinto tipo?
Bueno, lo que hace el C es armarse una tablita con todas las variables y las constantes, y memoriza el tipo de datos de cada dato.

Cuando declaramos una variable

int x;

el compilador de C no sólo reserva una posición de memoria para la x,
sino que además memoriza en alguna parte que esa posición de memoria es de cierto tipo, en esta caso "int".

Se trata de un atributo adicional de la variable, que suele ser invisible para nosotros.

Citar
printf("(-1 + cero)/2 = %d\n\n",  (-1 + cero) / 2 );

// Aquí se imprime un par de números separados por una coma. Creo, por lo que he ido viendo, que la instrucción %d llama a un tipo de variables o cosntantes (alfanuméricas, numéricas enteras, etc., según la letra que va detrás del %); en este caso parece que guarda el resultado  de  (-1 + cero)/2, pero no estoy seguro del todo de cómo funciona, es una instrucción muy nueva para mí que no recuerdo haber manejado mucho; leí que cuando es %c se refiere a variables tipo char o algo así pero poco más. El otro número detrás de la coma no va entre comillas, por tanto no es un valor “alfanumérico” (que digo yo en plan antiguo, no sé si se usa así todavía) con lo que la cuestión puede estar también relacionada con este tema del tipo de variables que resultan incompatibles según las instrucciones

En una futura ocasión voy a explicar mejor cómo funciona el printf().

Pero en esencia, la opción %d dice que en ese lugar se va poner un número, que es el primer dato o expresión que aparece después de la coma.

Algo más fácil de entender sería poner esto:

printf("Resultado: %d   ", (-1 + cero) /2);

Qué hace el printf acá no importa mucho.

Lo que importa es qué hace la simple y tonta suma.

El problema está en la cuenta (-1 + cero).
Eso es el meollo de todo.
Como cero lo hemos definido como 0, la cuenta (-1 + cero) tendría que darnos, según lo que sabemos tanto de matemática, como del lenguaje C, un simple valor -1.

Pero no nos da eso, sino cualquier otra cosa.
Ese otro número que da, "2 mil millones y pico", no importa cuánto es, ni cómo se forma, ni qué pasó con sus bits.
Eso no tiene importancia porque depende de cada compilador,
y no es algo que esté definido en el lenguaje C.

O sea que con otro compilador puede darnos cualquier otro número, equivocado o no.

El problema está en que hay unas ciertas reglas de conversión automática de tipos de datos que el lenguaje C exige, y ahí se arma el desastre.

El -1 es de tipo "signed int",
mientras que nuestra variable "cero" fue declarada de tipo "unsigned int".

No interesa acá si el -1 es negativo, positivo, 0, sino de qué tipo es.

Lo que hace el signo de suma +, antes de sumar, es convertir los tipos de datos de los sumandos.
Recién después efectúa la suma.
Son dos tareas las que hace el aparentemente inofensivo operador +.

Primero convierte ambos operandos al tipo "unsigned int".
No le importa qué le ocurre al -1 en esa conversión.
Luego los suma.

___________

Para distinguir mejor las cosas.
Supongamos que lo que hago es la suma (1 + cero).
La situación es la misma, sólo que en este caso no se ven los efectos.

Pero en este caso, en la suma (1 + cero),
el primer sumando, el 1, es considerado como "signed int", igual que el -1 de antes.
No importa que el 1 sea positivo. Se considera como un "entero con signo" de todos modos.

Como la variable "cero" es "unsigned", se aplica la misma regla de antes,
y así, primero se convierten ambos sumandos al tipo "unsigned int",
y recién después se suma.

_____________________________

En la matemática tenemos una situación similar al sumar enteros y naturales.

Si tenemos el número 1 del conjunto N de los naturales,
¿es lo mismo que el número 1 del conjunto Z de los enteros?
¿Se pueden sumar ambos?

La respuesta a esto es ambigua si no precisamos bien el contexto.

En principio, N y Z no tienen por qué ser compatibles,
o sea, no sabemos si N es un subconjunto de Z.

Sin embargo, sabemos que Z tiene un subconjunto Z+, que "funciona" igual que N.
Si "convertimos" los números de N (mediante una biyección) a números del subconjunto Z+ de Z, entonces ahora sí que podamos sumar ambos "1"s.

Lo que confunde es nuestro propio abuso de notación.

En la computadora pasa algo parecido: los tipos de datos distintos representan conjuntos de números distintos, y para poder mezclarlos, primero se tiene que hacer alguna clase de identificación, o conversión.

Si no se hiciera esto, directamente nos daría error por todas partes al compilar.

¿Qué significa todo esto?
Bueno, que el C tiene muchos tipos de datos numéricos, para distintas necesidades, y que el C intenta que todos esos tipos distintos sean compatibles entre sí, aún en malas situaciones.

El resultado es que pueden darse situaciones extrañas, difíciles de predecir, si no se programa con cuidado.


06 Enero, 2013, 07:43 pm
Respuesta #64

feriva

  • Matemático
  • Mensajes: 9,057
  • País: es
  • Karma: +1/-0
  • Sexo: Masculino
  • No soy matemático, eso es una etiqueta.


Primero convierte ambos operandos al tipo "unsigned int".
No le importa qué le ocurre al -1 en esa conversión.
Luego los suma.



Ah, claro, debería haber sospechado eso aunque no tenga experiencia con este lenguaje; porque cosas así, relacionadas con este tipo de despistes, me han pasado muchas veces con otros lenguajes y hasta con el HTML, que ya es decir; ya te puedes imaginar, con lo despistado que soy yo :D me pasa todo los días, con el ordenador y con todo.
 El ejemplo del conjunto de los naturales y los enteros me parece muy apropiado; y también meto en eso de vez en cuando la pata, el foro ya me habéis visto hacerlo unas cuantas veces, pero lo malo es que me pasa hasta a la hora de pagar cuando voy a la compra :D

Gracias; y no dejes el curso, que Mente oscura ha dicho por ahí que la hoja de cálculo se le queda pequeña para sus cosas de primos y necesita aprender a usar algo más potente; le he recomendado que lo siga.

Saludos. 

06 Enero, 2013, 07:59 pm
Respuesta #65

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Te hago un comentario adicional.

En lenguajes como BASIC o Pascal, no está permitido intercambiar ciertos tipos de datos distintos.

Sobretodo Pascal es muy restrictivo con ese tipo de cosas.

En Pascal no se puede sumar un "char" con un "integer", pero en C sí se puede.
El ejemplo de Pascal muestra más claro qué quiere decir tener tipos de datos distintos.
Son atributos de las variables, que no tienen nada que ver con el dato que guardan dentro de sí.

Las reglas de conversión de tipos de datos que sigue el C, no se fijan en ningún momento en el valor concreto que tienen las variables, sino sólo en cuál es el "tipo de datos" que tiene establecido.

Se hace luego una conversión de tipos, sin fijarse si tenemos albergado un 1 un -1, un 0, etc.
El compilador no se fija en esto cuando mezcla y convierte tipos.

Por eso no hay que marearse con el signo "-" del -1,
porque si fuera +1 el valor, al compilador le da lo mismo, ya que en ambos casos "ve" un "tipo de datos signed int".

06 Enero, 2013, 08:21 pm
Respuesta #66

feriva

  • Matemático
  • Mensajes: 9,057
  • País: es
  • Karma: +1/-0
  • Sexo: Masculino
  • No soy matemático, eso es una etiqueta.
Te hago un comentario adicional.

En lenguajes como BASIC o Pascal, no está permitido intercambiar ciertos tipos de datos distintos.



Nunca probé el Pascal, pero por lo que dices se ve que es de más alto nivel que el C, ya se sabe que cuanto más bajo es el nivel más fácil es equivocarse, son lenguajes más "pasotas", dejan hacer de todo y... antes de que te des cuenta se te bloquea el ordenador. No sé si el C será apropiado para mí :) (bueno, hoy en día, un programa, incluso un sistema operativo, se abre y se cierra en segundos; tampoco pasa nada)

06 Enero, 2013, 08:25 pm
Respuesta #67

pierrot

  • pabloN
  • Moderador Global
  • Mensajes: 3,395
  • País: uy
  • Karma: +0/-0
  • Sexo: Masculino
Sobre este punto estoy teniendo el cuidado de diferenciar hasta dónde el estándar asegura tal o cual cosa, y a partir de dónde es que ya no asegura nada, y las decisiones las toma el compilador que nosotros usamos.

En tu frase:

Citar
se puede investigar sobre cómo representa C cada tipo de datos.

Lo correcto sería decir "se puede investigar sobre cómo representa el compilador GCC cada tipo de datos".  ;) ;) ;)

Sí, ya veo que es así. Creí que había más uniformidad de criterios entre los compiladores pues, por ejemplo, tengo entendido que un "string" internamente no es más que un "array" de caracteres que termina en '\0' (el 00000000 de ASCII) y es así independientemente de los factores que mencionaste: el compilador usado, las opciones de compilación elegidas, la versión del sistema operativo en que corre, la máquina en que se está ejecutando, etcétera. Supuse que algo similar ocurriría con el tipo entero, al menos en lo que refiere a si usa complemento a dos, complemento a uno, desplazamiento o vaya a saber qué.

En la universidad lo que enseñan es a razonar algoritmos, y el lenguaje es tema secundario, lo cual está bien, porque uno tiene que aprender a pensar los problemas informáticos en forma independiente al lenguaje que está usando.

Exacto. De hecho, no estudiamos códigos sino pseudocódigos  :laugh:. Cuando le hablas a un profesor de una implementación particular, tiende a molestarse. Con ellos sólo se puede hablar a alto nivel. De hecho, los que dan teórico no están muy al tanto de los pormenores del lenguaje; los de práctico sí. Está relacionado con lo que tú decías al principio de que hay gente que parece no interesarle que un programa es algo que va a "aterrizar" a una computadora concreta en algún momento dado.

Ahora estoy con los tipos de datos, sin analizar los operadores, que son muchos.
Pero me parece muy bien la sugerencia, seguramente le dedicaré sus buenos capítulos.

Estaré atento  ;).

Creo que el problema podía estar en el tipo de datos que automáticamente se asigna a los números enteros.

Según las reglas de asignación de tipos, el 1 "intenta" ser un signed int, si es que cabe ahí.
Como cabe, lo pone de ese tipo.
Después, la operación (1 << k) conserva el tipo de datos, porque es sólo un corrimiento de bits.
El resultado será un entero positivo para k < 31 porque el bit de signo sigue siendo 0.
Mientras que para k = 31, el "1" ya ha llegado al bit de signo, el primero de todos: 1000000000...
En ese caso, como se trata de un signed int, el valor que toma es el de un número negativo, el más negativo de todos, digamos.

Claro, resulta el más negativo de todos.

El código siguiente:

for(k=0; k<=31; k=k+1)
      printf("k==%d: (1 << k) == %d\n  ",k, (1 << k));

Genera esta salida:

  k==0: (1 << k) == 1
  k==1: (1 << k) == 2
  k==2: (1 << k) == 4
  k==3: (1 << k) == 8
  k==4: (1 << k) == 16
  k==5: (1 << k) == 32
  k==6: (1 << k) == 64
  k==7: (1 << k) == 128
  k==8: (1 << k) == 256
  k==9: (1 << k) == 512
  k==10: (1 << k) == 1024
  k==11: (1 << k) == 2048
  k==12: (1 << k) == 4096
  k==13: (1 << k) == 8192
  k==14: (1 << k) == 16384
  k==15: (1 << k) == 32768
  k==16: (1 << k) == 65536
  k==17: (1 << k) == 131072
  k==18: (1 << k) == 262144
  k==19: (1 << k) == 524288
  k==20: (1 << k) == 1048576
  k==21: (1 << k) == 2097152
  k==22: (1 << k) == 4194304
  k==23: (1 << k) == 8388608
  k==24: (1 << k) == 16777216
  k==25: (1 << k) == 33554432
  k==26: (1 << k) == 67108864
  k==27: (1 << k) == 134217728
  k==28: (1 << k) == 268435456
  k==29: (1 << k) == 536870912
  k==30: (1 << k) == 1073741824
  k==31: (1 << k) == -2147483648

Hasta acá está andando todo tal cual lo imaginaba al momento de escribir el programa.

Podría ser alguna cuestión de la función printf (pero no, porque printf imprime correctamente datos de tipo signed int), así que podemos verificar el signo. Basta depurar con algo como:

   printf("%d\n", (1 << 31) < 0);

que dio salida "1" (verdadero).

Por otra parte, al hacer la máscara de bits con n = -2, que aparentemente, como vos decís, tiene representación complemento a dos,
el resultado de (n & (1 << 31)) tiene que dar esto: 1000000000000000.....

De nuevo, eso como signed int es el número -2147483648.

Sí, hasta ese punto no veo nada mal.

Cuando lo volvés a correr hacia la derecha con >> k, ¡va agregando 1's a la izquierda!  :o
El resultado de (n & (1 << k)) >> k, con k = 31, es 1111111111111.....  >:(

Pareciera que el corrimiento a derecha no funciona bien.

¡Ah, acá sí que esperaba algo distinto! Supuse que al "shiftear" a la derecha completaría con ceros, o sea, el resultado de (n & (1 << k)) >> k para k=31 debería dar

00000000000000000000000000000001

que es 1.

Al parecer esto no está bien definido en el estándar cuando se trata de números negativos.
Así que depende de la implementación.
Nuestro compilador lo que hace con el corrimiento a la derecha es conservar el bit de signo.

Si el número es positivo, hace lo que esperabas que hiciera, agrega 0's a la izquierda.
Pero si es negativo, agrega 1's por la izquierda, porque en cada corrimiento de los 31 que hace, va agregando un 1 por la izquierda...

Como 111111111111.... es la representación binaria de -1, eso explica el -1 al principio de la salida de tu programa.

Vaya, excelente análisis. Jamás se me cruzó por la cabeza que el shift a la derecha se comportara distinto que el shift a la izquierda.

Conclusión: El problema no es la representación binaria del -2, sino cómo se implementa en forma local (en el compilador) la operación de corrimiento a derecha.

Ya entiendo, muchas gracias  :).
$_="loe  hnachaPkr erttes,urJ";$j=0;for($i=0;s/(.)(.{$j})$//;$i++){$_=$2.$_,$j+=1-$i%2,print$1}print

06 Enero, 2013, 08:40 pm
Respuesta #68

pierrot

  • pabloN
  • Moderador Global
  • Mensajes: 3,395
  • País: uy
  • Karma: +0/-0
  • Sexo: Masculino
Te hago un comentario adicional.

En lenguajes como BASIC o Pascal, no está permitido intercambiar ciertos tipos de datos distintos.

Sobretodo Pascal es muy restrictivo con ese tipo de cosas.

En Pascal no se puede sumar un "char" con un "integer", pero en C sí se puede.
El ejemplo de Pascal muestra más claro qué quiere decir tener tipos de datos distintos.
Son atributos de las variables, que no tienen nada que ver con el dato que guardan dentro de sí.

Complemento la información agregando que a ese tipo de lenguajes se les denomina fuertemente tipados por las mismas razones que argentinator menciona.

Las reglas de conversión de tipos de datos que sigue el C, no se fijan en ningún momento en el valor concreto que tienen las variables, sino sólo en cuál es el "tipo de datos" que tiene establecido.

A esa conversión de tipos de datos prevista en el lenguaje para que se realice de forma "automática" (es decir, sin ser explicitada por el programador) se le suele denominar casting implícito.
$_="loe  hnachaPkr erttes,urJ";$j=0;for($i=0;s/(.)(.{$j})$//;$i++){$_=$2.$_,$j+=1-$i%2,print$1}print

06 Enero, 2013, 09:37 pm
Respuesta #69

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)

A esa conversión de tipos de datos prevista en el lenguaje para que se realice de forma "automática" (es decir, sin ser explicitada por el programador) se le suele denominar casting implícito.

Gracias por todas tus aportaciones.

A veces no sé el nombre técnico,
y a veces lo sé, pero no lo uso a propósito, para no introducir tanta terminología, y no perder de vista la descripción concreta de lo que estamos haciendo.


06 Enero, 2013, 11:53 pm
Respuesta #70

feriva

  • Matemático
  • Mensajes: 9,057
  • País: es
  • Karma: +1/-0
  • Sexo: Masculino
  • No soy matemático, eso es una etiqueta.


En una futura ocasión voy a explicar mejor cómo funciona el printf().

Pero en esencia, la opción %d dice que en ese lugar se va poner un número, que es el primer dato o expresión que aparece después de la coma.


 Sí observé que localiza lo que se imprime más para allá o más para acá a modo de espaciador, o sea


printf("(-1 + cero)/2 = %d\n\n",  (-1 + cero) / 2 );


printf("(-1 + cero)/2 =                   %d\n\n",  (-1 + cero) / 2 );

así aparecería la respuesta más lejos del singo igual.

Pero no sé qué trascendencia tiene que sea una "d", una "c", no sé si es verdaderamente importante, porque probé a cambiar la letra en algunos sitios y funcionaba lo mismo; es decir, no sé si en algunos casos poner una letra inadecuada, según el tipo de variable, puede dar lugar a un error que estropee el programa o se puede uno despreocupar de ello.

Buenas noches.

07 Enero, 2013, 12:07 am
Respuesta #71

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Citar
Pero no sé qué trascendencia tiene que sea una "d", una "c", no sé si es verdaderamente importante, porque probé a cambiar la letra en algunos sitios y funcionaba lo mismo; es decir, no sé si en algunos casos poner una letra inadecuada, según el tipo de variable, puede dar lugar a un error que estropee el programa o se puede uno despreocupar de ello.

Sí es importante, pero todavía no lo voy a explicar.

Hasta ahora he usado el printf() sólo como una forma rápida de mostrar en la pantalla los resultados de lo que estamos haciendo.

Por eso no lo explico demasiado.
Fijate que al principio ni siquiera le pasaba datos, sólo era texto.

Es importante explicar en detalle el printf(), por eso lo estoy postergando.


07 Enero, 2013, 01:46 pm
Respuesta #72

feriva

  • Matemático
  • Mensajes: 9,057
  • País: es
  • Karma: +1/-0
  • Sexo: Masculino
  • No soy matemático, eso es una etiqueta.

Me parece que en este caso lo más adecuado sería hacer una pausa con una llamada al sistema, así:

system("PAUSE");

previamente adosando la librería stdlib.h

______________




#include <stdlib.h>
#include <stdio.h>

void main(void)

{
   int a;

    printf("Escriba un numero: ");
   
    scanf(" %d", &a);

    if(a>0)
        printf("Es positivo\n\n");
   
   system("PAUSE");

 }



 Una cosa que se me pasó. Éste funciona, pero quitando el "Void", si no, me manda un mensaje que dice algo así como que el "main" debe retornar a "int" (yo de inglés no sé mucho, pero es lo que entiendo). Supongo que tendrá que ver con la nueva librería añadida y la función Void ¿no?

 Saludos.

07 Enero, 2013, 02:26 pm
Respuesta #73

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
La  verdad no sé qué decirte, porque a mí me funciona sin problemas, ni avisos de ningún tipo.

No tendría por qué haber problemas.

¿Habrás tocado opciones de la configuración?

Yo no he tocado nada, salvo la opción que da al compilador "soporte para ANSI".
Pero igual esto no afecta en nada.

Si necesitás un int en vez de un void, usalo y listo.
Es más correcto y todo:

int main(void)

07 Enero, 2013, 02:47 pm
Respuesta #74

feriva

  • Matemático
  • Mensajes: 9,057
  • País: es
  • Karma: +1/-0
  • Sexo: Masculino
  • No soy matemático, eso es una etiqueta.
La  verdad no sé qué decirte, porque a mí me funciona sin problemas, ni avisos de ningún tipo.

No tendría por qué haber problemas.

¿Habrás tocado opciones de la configuración?

Yo no he tocado nada, salvo la opción que da al compilador "soporte para ANSI".
Pero igual esto no afecta en nada.

Si necesitás un int en vez de un void, usalo y listo.
Es más correcto y todo:

int main(void)

Pues será cosa de la configuración mía lo más seguro; no pasa nada, te lo decía por curiosidad.

Saludos.

07 Enero, 2013, 08:31 pm
Respuesta #75

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Anuncios (que considero) importantes:

Una lectura más cuidadosa de las normas del estándar C de 1999 (el C99) me ha llevado a darme cuenta de que hay cosas que escribí sobre los tipos de datos enteros que no eran del todo correctas.

* No se puede hablar de los bytes que ocupa un tipo de datos entero, sino que el estándar obliga a especificar sólo su "rango de valores".

Es distinto hablar del tamaño en bits o bytes que un dato ocupa en memoria, que el rango de números asignado a un tipo de datos.

Eso me obligó a modificar detalles en este post:

Enteros en C

Además agregué unos tipos de datos de la librería stdint.h que antes no había considerado: los "rápidos" (int_fast8_t, int_fast16_t, etc.) y los asociados a punteros (intptr_t, uintptr_t).



Otra sutileza importante es el tema de qué diablos es un BYTE.
Casi que eliminé la palabra BYTE de todo el post,
porque el estándar C99 deja un byte a libre interpretación.

Cada compilador decide cuántos bits son un byte.
La cantidad de bits en cuestión se ha de definir en el archivo limits.h, con la macro CHAR_BIT.
Luego, un char debe ocupar un byte, eso sí, pero de la cantidad de bits es la indicada en CHAR_BIT.



En el post inmediato siguiente (http://rinconmatematico.com/foros/index.php?topic=64835.msg260468#msg260468) estoy haciendo una continuación del análisis de los tipos de datos enteros.

Es necesario hacerlo antes de largarnos a hacer un programita que tengo en mente, que pondrá a prueba todos los rangos de valores de los tipos de datos de números enteros en C.

Aún está en edición.

Pero lo más grave es que voy a tener que tragarme estas palabras mías:

Citar
El lenguaje C no es lenguaje de máquina, y entonces la manera en que se representan internamente los datos depende de cada compilador.
No es algo que te puedas aprender, porque no está fijado por las reglas del lenguaje C.

Un programador en C no tiene por qué saber o supone cómo se representan los números (o cualquier dato) internamente.

A partir del estándar de 1999 estas especificaciones se dan en forma precisa, bit a bit, y sólo unos pocos detalles se dejan sin especificar.

Originalmente el lenguaje C era quizás como yo decía, y la representación interna bit a bit podía suponerse "oscura" y "arbitraria", decidida finalmente por el compilador o sistema de turno.

Pero el estándar C99 obliga a que todos los compiladores cumplan con las mismas normas.

Hay pocas cosas que no obliga. Por ejemplo, no te dice si los enteros signados usarán complemento a 2 o complemento a 1.
No obstante, te indica qué debe ocurrir en cada caso, y no da lugar a muchas otras posibilidades.

Esos detalles los estuve explicando en el referido post, aunque todavía no lo he podido terminar. Conlleva mucha información que quiero apuntar y dejar bien organizada.

Está en borrador todavía...

08 Enero, 2013, 02:04 am
Respuesta #76

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Terminé por fin con todos los detalles técnicos de los tipos de datos enteros.  :banghead: :banghead: :banghead:

¡Es terrible este tema!

He sufrido mucho escribiendo esos dos pots.   :'( :'( :'( :'( :'(

El primero sólo lo retoqué en un par de párrafos, y el 2do terminé de editarlo.
Ahí van (no hagan caso del post que sigue después de un programa que lee archivos de texto, que está descolgado del tema).

Enteros en C (parte I)
Enteros en C (parte II)

08 Enero, 2013, 02:15 am
Respuesta #77

feriva

  • Matemático
  • Mensajes: 9,057
  • País: es
  • Karma: +1/-0
  • Sexo: Masculino
  • No soy matemático, eso es una etiqueta.
Terminé por fin con todos los detalles técnicos de los tipos de datos enteros.  :banghead: :banghead: :banghead:

¡Es terrible este tema!

He sufrido mucho escribiendo esos dos pots.   :'( :'( :'( :'( :'(

El primero sólo lo retoqué en un par de párrafos, y el 2do terminé de editarlo.
Ahí van (no hagan caso del post que sigue después de un programa que lee archivos de texto, que está descolgado del tema).

Enteros en C (parte I)
Enteros en C (parte II)

Lo he estado mirando por encima y mañana lo miraré más despacio; ahora, esto es para consultar mientras se hacen los programas e ir viéndolo despacio, porque, si no, no se graba en "mi disco duro" use base octal, binaria o cualquier otra que use  :P

Saludos y hasta mañana,

08 Enero, 2013, 02:41 am
Respuesta #78

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Todo el manejo de los tipos de datos enteros es muy engorroso, complicado, lleno de excepciones, consideraciones, vueltas y contratuercas.

No es como en matemática que sólo hay naturales y enteros.
En C es un desastre.

Así que se trata de algo que hay que leer varias veces, incluso en períodos distanciados de tiempo,
hasta lograr terminar de entenderlo, una cosa a la vez.

Más aún, se trata de una discusión completamente técnica.
Me costó porque no quería dejar la tarea incompleta.
Pero yo diría que los dos posts que escribí sobre este tema son, sobretodo, para tenerlos de referencia técnica, no para aprendérselos de memoria.

Sin embargo, sí que me parece apropiado leer al menos una vez todo eso, porque hay que saber que todos esos tipos de datos existen en C, y que hay ciertos manejos internos que se hacen con ellos, de un modo u otro.

El primero de los dos posts es el más importante.
Es fundamental entenderlo lo mejor que se pueda, porque contiene los tipos de datos enteros básicos de C, y que aparecen automáticamente en los programas, nos guste o no.

En cambio, podemos vivir largos años sin necesitar nada del 2do post.

Saludos

08 Enero, 2013, 02:46 am
Respuesta #79

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,272
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)