Largo largo en c99

Jan 10 2021

En el estándar C99 lo introdujeron long long. ¿Cuál es el propósito de esto? En mi (limitada) experiencia de programación en C, solo he visto un int de 4 bytes y uno de 8 bytes de longitud. Por ejemplo, desde Compiler Explorer:

Si longya es 8entonces, ¿por qué es necesario agregar otro long longtipo? ¿Qué le hace esto al compilador / arquitectura?

Respuestas

6 chux-ReinstateMonica Jan 10 2021 at 05:36

Si long ya es 8, ¿por qué es necesario agregar otro tipo long long? ¿Qué le hace esto al compilador / arquitectura?

"Si long ya es 8" no siempre es cierto, ya que existe mucho código que se basa en 32 bits longy int32 o 16 bits.

Requerir longcomo 64 bits rompería las bases del código. Ésta es una gran preocupación.


Sin embargo, requerir longpermanecer en 32 bits (y no long long) no daría acceso a números enteros estándar de 64 bits, de ahí que sea una justificación long long.

Permitir longcomo 32 bits o 64 bits (u otros) permite la transición.

Varias funciones pasan / regresan longcomo fseek(), ftell(). Se benefician de longtener más de 32 bits para admitir archivos grandes.

La práctica recomendada fomenta una más amplia long: "Los tipos utilizados para size_ty ptrdiff_tno deben tener un rango de conversión de números enteros mayor que el de a signed long intmenos que la implementación admita objetos lo suficientemente grandes como para que esto sea necesario". Esto se relaciona con tamaños de memoria que exceden los 32 bits.


Quizás en el futuro una implementación pueda usar int/long/long long/intmax_tcomo 32/64/128/256 bits.

IAC, veo que los tipos de ancho fijo intN_taumentan en popularidad sobre longy long long. Tiendo a usar tipos de ancho fijo o bool, ( unsigned) char, int/ unsigned,, size_t( u) intmax_ty dejar signed char, ( unsigned) short, ( unsigned) long, ( unsigned) long longpara casos especiales.

4 dbush Jan 10 2021 at 05:26

El estándar C solo garantiza que an intpuede tener (en términos generales) 2 bytes, a longpuede tener 4 bytes y a long longpuede tener 8 bytes.

De hecho, MSVC todavía usa 4 bytes longa pesar de que tiene 4 bytes int.

3 NateEldredge Jan 10 2021 at 05:38

El único requisito relevante para inty long, entonces y ahora, es que intdebe tener al menos 16 bits y longdebe tener al menos 32 bits. Los sistemas de 16 y 32 bits tienden a tener 32 bits long, y las máquinas de 64 bits eran mucho menos comunes a fines de la década de 1990. Entonces, antes de C99, los programadores no podían confiar de manera portátil en tener un tipo entero de 64 bits disponible en absoluto. Ese problema se resolvió con la introducción de long long, que debe tener al menos 64 bits. (Creo que GCC y tal vez otros compiladores ya lo proporcionaron como una extensión).

En estos días, muchos (pero no todos) los sistemas de 64 bits usan 64 bits longy no se molestan en hacerlos long longmás grandes, por lo que también son de 64 bits y, en cierto sentido, son redundantes. Es de suponer que esos son los sistemas con los que está familiarizado, pero no representan todo lo que existe.

2 PeterCordes Jan 10 2021 at 10:29

Creo que no se dio cuenta de que está haciendo una gran suposición errónea sobre cómo funcionan los requisitos de ancho de tipo C: ISO C solo establece un rango de valores mínimo como la magnitud más pequeña permitida LONG_MAXy LONG_MIN(-2147483647, no 8 porque ISO C permite el complemento de uno y los enteros con signo / magnitud con signo, no solo el complemento de 2). Las implementaciones reales pueden tener tipos más amplios, a menudo para coincidir con un ancho de registro o un tamaño de operando que la máquina de destino puede hacer de manera eficiente.

Se ha escrito mucho sobre esto en Stack Overflow y en otros lugares, que no intentaré repetir aquí. Ver tambiénhttps://en.cppreference.com/w/c/language/arithmetic_types


Eso lo llevó al error de mirar las opciones de ancho de tipo en la ABI de System V x86-64 y asumir que otras implementaciones de C son iguales, creo. x86-64 es un ISA de 64 bits que puede funcionar de manera eficiente con enteros de 64 bits, por lo que 64 bits longfue una elección bastante sensata.

Ningún ABI sano para una máquina de 32 bits como i386 usaría 64 bits longporque no es necesario, solo 32 bits. El uso de 64 bits significaría que no podría caber en un solo registro. Compile -m32o compile para ARM de 32 bits. Godbolt también tiene GCC para AVR y MSP430. En esas máquinas de 8 y 16 bits, GCC elige los anchos más pequeños permitidos por ISO C (2 bytes int, etc.)

En 1999, x86-64 ni siquiera existía. (Algunas otras ISA de 64 bits lo hicieron, como Alpha). Por lo tanto, mirar una de las 2 ABI principales para que comprenda las opciones de C99 no lo llevará muy lejos.

Por supuesto, C necesita un tipo que esté garantizado para ser de al menos 64 bits, para permitir que las personas escriban programas que realicen cálculos matemáticos enteros de 64 bits de manera eficiente.


Y por cierto, x86-64 puede hacer cosas enteras de 32 bits tan eficientemente como 64 bits, a veces de manera más eficiente. Por lo longtanto, podría decirse que hacer un tipo de 64 bits no es genial. Algunos códigos se usan longporque quieren un tipo que debe ser de 32 bits, pero no se beneficia de tenerlo más ancho. Para tal código, 64 bits longsolo desperdicia espacio de memoria caché / ancho de banda de memoria y tamaño de código (prefijos REX). En C99, la opción ideal sería int_least32_t, pero es molestamente largo de escribir y rara vez se usa.

Pero a longveces se espera que OTOH sea ​​"el tipo más eficiente (1 registro)", aunque no existe tal garantía y las ABI LLP64 como Windows x64 con 32 bits longno son así.

Otra lata de gusanos es C99 int_fast32_ty x86-64 System V, la mala elección de la OMI de System V para convertirlo en un tipo de 64 bits. (Tengo una respuesta a medio escribir para Cpp uint32_fast_t se resuelve en uint64_t pero es más lento para casi todas las operaciones que un uint32_t (x86_64). ¿Por qué se resuelve en uint64_t? Lo que debería terminar ... int_fast32_tplantea la pregunta de "rápido para qué propósito ", y en muchas implementaciones no es lo que esperarías en muchos casos.

Ver también

  • C ++: ¿el tipo de entero más rápido?
  • ¿Cómo se deben definir los tipos [u] int_fastN_t para x86_64, con o sin la ABI x32?
  • ¿Por qué se preferiría uint32_t en lugar de uint_fast32_t?
  • ¿Por qué uint_least16_t es más rápido que uint_fast16_t para la multiplicación en x86_64?
  • Optimizaciones del compilador permitidas a través de los tipos de ancho no fijo "int", "mínimo" y "rápido" C / C ++
old_timer Jan 11 2021 at 06:16

Hay algunos límites, pero el autor del compilador es libre de elegir las longitudes de los tipos de variables C estándar (char, short, int, long, long long). Naturalmente, char va a ser un byte para esa arquitectura (la mayoría con compiladores de C son de 8 bits). Y, naturalmente, no puede hacer que algo más pequeño sea más grande que algo más grande, long no puede ser más pequeño que un int. Pero ciertamente en 1999 vimos la transición x86 de 16 a 32 bits y, por ejemplo, int cambió de 16 a 32 con varias herramientas, pero permaneció durante mucho tiempo en 32. Más tarde, ocurrió la transición x86 de 32 a 64 bits y, según la herramienta, había tipos disponibles. ayudar.

El problema existía mucho antes de esto y la solución no fue fijar las longitudes de los tipos, están, dentro de las reglas, hasta los autores del compilador en cuanto al tamaño. Pero los autores del compilador deben crear un archivo stdint.h que coincida con la herramienta y el objetivo (stdint.h es específico de una herramienta y un objetivo como mínimo y puede ser una versión de la herramienta y opciones de compilación para esa herramienta, etc.). De modo que, por ejemplo, uint32_t siempre es de 32 bits. Algunos autores convertirán eso en int, otros en long, etc. en su stdint.h. Los tipos de variables del lenguaje C permanecen limitados a char, short, int, etc. según el lenguaje (uint32_t no es un tipo de variable, se convierte a un tipo de variable a través de stdint.h). Esta solución / solución alternativa fue una forma de evitar que todo se volviera loco y mantener vivo el lenguaje.

Los autores suelen elegir, por ejemplo, si los GPR son de 16 bits para que int sea de 16 bits, y si los de 32 bits sean de 32 bits, etc., pero tienen cierta libertad.

Sí, esto significa específicamente que no hay razón para suponer que dos herramientas para un objetivo en particular (la computadora en la que está leyendo esto, por ejemplo) usen las mismas definiciones para int y long en particular, y si desea escribir código para esta plataforma que puede migrar a través de estas herramientas (que admiten esta plataforma) luego use los tipos stdint.h y no int, long, etc ... Lo más seguro es que si está cruzando plataformas, una mcu msp430, una mcu arm, una máquina arm linux , una máquina basada en x86, que los tipos, incluso para la misma "cadena de herramientas" (gnu gcc y binutils, por ejemplo), no tienen las mismas definiciones para int y long, etc. char y short tienden a ser de 8 y 16 bits, int y long tienden a variar más, a veces del mismo tamaño entre sí, a veces diferentes, pero el punto es no asumir.

Es trivial detectar los tamaños, para una versión del compilador / destino / opciones de línea de comando, o simplemente seguir la ruta estándar para minimizar los problemas más adelante.