
Khaloymes
En una tarea reciente me dijeron que usara long
variable para almacenar un resultado, ya que puede ser un número grande.
Decidí verificar si realmente me importa, en mi sistema (compilador Intel Core i5/64-bit Windows 7/gnu gcc) y descubrí que el siguiente código:
printf("sizeof(char) => %d\n", sizeof(char));
printf("sizeof(short) => %d\n", sizeof(short));
printf("sizeof(short int) => %d\n", sizeof(short int));
printf("sizeof(int) => %d\n", sizeof(int));
printf("sizeof(long) => %d\n", sizeof(long));
printf("sizeof(long int) => %d\n", sizeof(long int));
printf("sizeof(long long) => %d\n", sizeof(long long));
printf("sizeof(long long int) => %d\n", sizeof(long long int));
produce la siguiente salida:
sizeof(char) => 1
sizeof(short) => 2
sizeof(short int) => 2
sizeof(int) => 4
sizeof(long) => 4
sizeof(long int) => 4
sizeof(long long) => 8
sizeof(long long int) => 8
En otras palabras, en mi sistema, int
y long
son iguales, y lo que sea será demasiado grande para int
para sostener, será demasiado grande para long
para sostener también.
La tarea en sí no es el problema aquí. Me pregunto cómo, en un sistema donde int < long
¿debo asignar un int
mucho tiempo?
Soy consciente del hecho de que hay numerosas preguntas estrechamente relacionadas sobre este tema, pero siento que las respuestas dentro de ellas no me brindan una comprensión completa de lo que sucederá o puede suceder en el proceso.
Básicamente estoy tratando de averiguar lo siguiente:
- ¿Debería lanzar
long
para int
antes de la asignación, o ya que long
no es un tipo de datos diferente, sino simplemente un modificador, se considerará inofensivo ceder directamente?
- ¿Qué sucede en los sistemas donde
long > int
? ¿Será el resultado indefinido (o impredecible) o hará que se omitan las partes adicionales de la variable?
- ¿Cómo funciona el casting de
long
para int
funciona en C?
- ¿Cómo funciona la tarea de
long
para int
funciona en C cuando no uso el casting?

keith thompson
El lenguaje garantiza que int
es de al menos 16 bits, long
es de al menos 32 bits, y long
puede representar por lo menos todos los valores que int
puede representar.
Si asignas un long
valor a un int
objeto, se convertirá implícitamente. No hay necesidad de un reparto explícito; simplemente especificaría la misma conversión que ocurrirá de todos modos.
En su sistema, donde int
y long
tiene el mismo tamaño y rango, la conversión es trivial; simplemente copia el valor.
en un sistema donde long
es más ancho que int
si el valor no cabe en un int
, entonces el resultado de la conversión está definido por la implementación. (O, a partir de C99, puede generar una señal definida por la implementación, pero no conozco ningún compilador que realmente haga eso). típicamente sucede es que los bits de orden superior se descartan, pero no debe depender de eso. (Las reglas son diferentes para los tipos sin signo; el resultado de convertir un entero con signo o sin signo en un tipo sin signo está bien definido).
Si lo necesitas sin peligro asignar un long
valor a un int
objeto, puedes comprobar que encajará antes de hacer la tarea:
#include <limits.h> /* for INT_MIN, INT_MAX */
/* ... */
int i;
long li = /* whatever */
if (li >= INT_MIN && li <= INT_MAX) {
i = li;
}
else {
/* do something else? */
}
Los detalles de “algo más” van a depender de lo que quieras hacer.
Una corrección: int
y long
están siempre tipos distintos, incluso si tienen el mismo tamaño y representación. Los tipos aritméticos se pueden convertir libremente, por lo que a menudo esto no hace ninguna diferencia, pero por ejemplo int*
y long*
son tipos distintos e incompatibles; no puedes asignar un long*
a una int*
o viceversa, sin un elenco explícito (y potencialmente peligroso).
Y si necesita convertir un long
valor a int
, lo primero que debe hacer es reconsiderar el diseño de su código. A veces, tales conversiones son necesarias, pero más a menudo son una señal de que el int
al que está asignando debería haber sido definido como un long
en primer lugar.
A long
siempre puede representar todos los valores de int
. Si el valor en cuestión se puede representar mediante el tipo de variable que asigna, el valor se conserva.
Si no se puede representar, entonces para el tipo de destino firmado, el resultado no se especifica formalmente, mientras que para el tipo de destino no firmado se especifica como el valor original módulo 2nortedonde norte es el número de bits en la representación del valor (que no es necesariamente todos los bits en el destino).
En la práctica, en las máquinas modernas también se envuelven los tipos firmados.
Eso es porque las máquinas modernas usan forma de complemento a dos para representar enteros con signo, sin ningún bit utilizado para indicar “valor no válido” o similar, es decir, todos los bits utilizados para la representación del valor.
Con norte representación del valor de los bits cualquier valor entero es X está asignado a X+K*2norte con la constante entera K elegida de manera que el resultado esté en el rango donde la mitad de los valores posibles son negativos.
Así, por ejemplo, con 32 bits int
el valor -7 se representa como número de patrón de bits -7+232 = 232-7, de modo que si muestra el número que representa el patrón de bits como un entero sin signo, obtiene un número bastante grande.
La razón por la que esto se llama complemento a dos es porque tiene sentido para el sistema numérico binario, el sistema numérico de base dos. Para el sistema numérico binario también hay un complemento de unos (nótese la ubicación del apóstrofo). De manera similar, para el sistema numérico decimal existe el complemento de diez y el complemento de nueve. Con la representación del complemento de diez de 4 dígitos representarías -7 como 10000-7 = 9993. Eso es todo, de verdad.
C tiene modificadores (
volatile
,const
), peroshort
,long
,signed
yunsigned
están NO modificadores Especifican tipos únicos.– Pato mugido
30 de noviembre de 2012 a las 20:24
Cuidado ahí. Si tuviera que mirar, digamos, un sistema Linux AMD64. long es de 8 bytes donde como int en 4. Ver en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models para algunos casos comunes.
– usuario507577
30 de noviembre de 2012 a las 20:24
@Rajesh: no creo que tenga nada que ver con el sistema operativo o hardware. El tamaño de los tipos es una decisión (en su mayoría) arbitraria del compilador.
– Pato mugido
30 de noviembre de 2012 a las 20:27
@MooingDuck y cuando todos los compiladores de una plataforma hacen lo mismo, está más o menos resuelto 🙂
– usuario507577
30 de noviembre de 2012 a las 20:31
@MooingDuck: la decisión tomada por el compilador (más exactamente, por sus autores) está fuertemente influenciada por el sistema operativo y el hardware. Muchos sistemas tienen una ABI que especifica tamaños de tipos enteros; seguirlo hace posible mezclar código compilado por diferentes compiladores. En algunos casos, la compatibilidad con versiones anteriores es una gran influencia, lo que a veces da como resultado cosas como 32 bits
long
en un sistema de 64 bits.–Keith Thompson
30 de noviembre de 2012 a las 20:36