¿Cómo son los tipos de datos C “soportados directamente por la mayoría de las computadoras”?

Estoy leyendo “The C Programming Language” de K&R y me encontré con esta statement [Introducción, pág. 3]:

Debido a que los tipos de datos y las estructuras de control provistas por C son compatibles directamente con la mayoría de las computadoras , la biblioteca de tiempo de ejecución requerida para implementar progtwigs independientes es muy pequeña.

¿Qué significa la statement en negrita? ¿Hay un ejemplo de un tipo de datos o una estructura de control que no es compatible directamente con una computadora?

Sí, hay tipos de datos que no son compatibles directamente.

En muchos sistemas integrados, no hay una unidad de punto flotante de hardware. Entonces, cuando escribes código como este:

float x = 1.0f, y = 2.0f; return x + y; 

Se traduce en algo como esto:

 unsigned x = 0x3f800000, y = 0x40000000; return _float_add(x, y); 

Luego, el comstackdor o la biblioteca estándar debe proporcionar una implementación de _float_add() , que ocupa memoria en su sistema integrado. Si está contando bytes en un sistema realmente pequeño, esto puede sumr.

Otro ejemplo común son los enteros de 64 bits ( long long en el estándar C desde 1999), que no son compatibles directamente con los sistemas de 32 bits. Los sistemas SPARC antiguos no admitían la multiplicación de enteros, por lo que la runtime tenía que proporcionarla. Hay otros ejemplos.

Otros idiomas

En comparación, otras lenguas tienen primitivas más complicadas.

Por ejemplo, un símbolo Lisp requiere una gran cantidad de soporte de tiempo de ejecución, al igual que las tablas en Lua, las cadenas en Python, los arreglos en Fortran, etc. Los tipos equivalentes en C generalmente no son parte de la biblioteca estándar (no son símbolos o tablas estándar) o son mucho más simples y no requieren mucho soporte de tiempo de ejecución (los arreglos en C son básicamente solo punteros, las cadenas terminadas en nulos son casi tan simple).

Estructuras de Control

Una estructura de control notable que falta en C es el manejo de excepciones. La salida no local está limitada a setjmp() y longjmp() , que solo guarda y restaura ciertas partes del estado del procesador. En comparación, el tiempo de ejecución de C ++ tiene que recorrer la stack y llamar a los destructores y a los controladores de excepciones.

En realidad, apuesto a que los contenidos de esta introducción no han cambiado mucho desde 1978, cuando Kernighan y Ritchie los escribieron por primera vez en la Primera Edición del libro, y se refieren a la historia y evolución de C en ese momento más que a la moderna. implementaciones

Las computadoras son fundamentalmente bancos de memoria y procesadores centrales, y cada procesador funciona con un código de máquina; parte del diseño de cada procesador es una architecture de conjunto de instrucciones, llamada Lenguaje de ensamblaje , que se asigna de uno a uno de un conjunto de mnemotécnicos legibles a códigos de máquina, que son todos los números.

Los autores del lenguaje C, y los lenguajes B y BCPL que lo precedieron inmediatamente, intentaron definir constructos en el lenguaje que se comstackron de la manera más eficiente posible en la Asamblea … de hecho, se vieron obligados a cumplir las limitaciones del objective. hardware. Como han señalado otras respuestas, esto implicaba twigs (GOTO y otro control de flujo en C), movimientos (asignación), operaciones lógicas (& | ^), aritmética básica (sum, resta, incremento, disminución) y direccionamiento de memoria (punteros). ). Un buen ejemplo son los operadores pre / post-incremento y decremento en C, que supuestamente fueron agregados al lenguaje B por Ken Thompson específicamente porque eran capaces de traducir directamente a un solo código de operación una vez comstackdo.

Esto es lo que querían decir los autores cuando decían “admitido directamente por la mayoría de las computadoras”. No querían decir que otros idiomas contuvieran tipos y estructuras que no se admitían directamente; significaban que, mediante el diseño C, las construcciones se traducían más directamente (a veces literalmente directamente) en Ensamblaje.

Esta estrecha relación con la Asamblea subyacente, aunque sigue proporcionando todos los elementos necesarios para la progtwigción estructurada, es lo que llevó a la adopción temprana de C, y lo que la mantiene como un lenguaje popular hoy en día en los que la eficiencia del código comstackdo sigue siendo clave.

Para una interesante reseña de la historia del lenguaje, vea El desarrollo del lenguaje C – Dennis Ritchie

La respuesta corta es que la mayoría de las construcciones de lenguaje compatibles con C también son compatibles con el microprocesador de la computadora de destino, por lo tanto, el código C comstackdo se traduce de manera muy agradable y eficiente al lenguaje ensamblador del microprocesador, lo que resulta en un código más pequeño y una huella más pequeña.

La respuesta más larga requiere un poco de conocimiento del lenguaje ensamblador. En C, una statement como esta:

 int myInt = 10; 

se traduciría a algo como esto en ensamblaje:

 myInt dw 1 mov myInt,10 

Compara esto con algo como C ++:

 MyClass myClass; myClass.set_myInt(10); 

El código del lenguaje ensamblador resultante (dependiendo de cuán grande sea MyClass ()), podría agregar hasta cientos de líneas de lenguaje ensamblador.

Sin crear progtwigs en lenguaje ensamblador, C puro es probablemente el código “más delgado” y “más ajustado” en el que puede crear un progtwig.

EDITAR

Dados los comentarios en mi respuesta, decidí realizar una prueba, solo por mi propia cordura. Creé un progtwig llamado “test.c”, que se veía así:

 #include  void main() { int myInt=10; printf("%d\n", myInt); } 

Compilé esto hasta el ensamblaje usando gcc. Usé la siguiente línea de comandos para comstackrla:

 gcc -S -O2 test.c 

Aquí está el lenguaje ensamblador resultante:

  .file "test.c" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "%d\n" .section .text.unlikely,"ax",@progbits .LCOLDB1: .section .text.startup,"ax",@progbits .LHOTB1: .p2align 4,,15 .globl main .type main, @function main: .LFB24: .cfi_startproc movl $10, %edx movl $.LC0, %esi movl $1, %edi xorl %eax, %eax jmp __printf_chk .cfi_endproc .LFE24: .size main, .-main .section .text.unlikely .LCOLDE1: .section .text.startup .LHOTE1: .ident "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1" .section .note.GNU-stack,"",@progbits 

Luego creo un archivo llamado “test.cpp” que definió una clase y dio como resultado lo mismo que “test.c”:

 #include  using namespace std; class MyClass { int myVar; public: void set_myVar(int); int get_myVar(void); }; void MyClass::set_myVar(int val) { myVar = val; } int MyClass::get_myVar(void) { return myVar; } int main() { MyClass myClass; myClass.set_myVar(10); cout << myClass.get_myVar() << endl; return 0; } 

Lo compilé de la misma manera, usando este comando:

 g++ -O2 -S test.cpp 

Aquí está el archivo de ensamblaje resultante:

  .file "test.cpp" .section .text.unlikely,"ax",@progbits .align 2 .LCOLDB0: .text .LHOTB0: .align 2 .p2align 4,,15 .globl _ZN7MyClass9set_myVarEi .type _ZN7MyClass9set_myVarEi, @function _ZN7MyClass9set_myVarEi: .LFB1047: .cfi_startproc movl %esi, (%rdi) ret .cfi_endproc .LFE1047: .size _ZN7MyClass9set_myVarEi, .-_ZN7MyClass9set_myVarEi .section .text.unlikely .LCOLDE0: .text .LHOTE0: .section .text.unlikely .align 2 .LCOLDB1: .text .LHOTB1: .align 2 .p2align 4,,15 .globl _ZN7MyClass9get_myVarEv .type _ZN7MyClass9get_myVarEv, @function _ZN7MyClass9get_myVarEv: .LFB1048: .cfi_startproc movl (%rdi), %eax ret .cfi_endproc .LFE1048: .size _ZN7MyClass9get_myVarEv, .-_ZN7MyClass9get_myVarEv .section .text.unlikely .LCOLDE1: .text .LHOTE1: .section .text.unlikely .LCOLDB2: .section .text.startup,"ax",@progbits .LHOTB2: .p2align 4,,15 .globl main .type main, @function main: .LFB1049: .cfi_startproc subq $8, %rsp .cfi_def_cfa_offset 16 movl $10, %esi movl $_ZSt4cout, %edi call _ZNSolsEi movq %rax, %rdi call _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ xorl %eax, %eax addq $8, %rsp .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE1049: .size main, .-main .section .text.unlikely .LCOLDE2: .section .text.startup .LHOTE2: .section .text.unlikely .LCOLDB3: .section .text.startup .LHOTB3: .p2align 4,,15 .type _GLOBAL__sub_I__ZN7MyClass9set_myVarEi, @function _GLOBAL__sub_I__ZN7MyClass9set_myVarEi: .LFB1056: .cfi_startproc subq $8, %rsp .cfi_def_cfa_offset 16 movl $_ZStL8__ioinit, %edi call _ZNSt8ios_base4InitC1Ev movl $__dso_handle, %edx movl $_ZStL8__ioinit, %esi movl $_ZNSt8ios_base4InitD1Ev, %edi addq $8, %rsp .cfi_def_cfa_offset 8 jmp __cxa_atexit .cfi_endproc .LFE1056: .size _GLOBAL__sub_I__ZN7MyClass9set_myVarEi, .-_GLOBAL__sub_I__ZN7MyClass9set_myVarEi .section .text.unlikely .LCOLDE3: .section .text.startup .LHOTE3: .section .init_array,"aw" .align 8 .quad _GLOBAL__sub_I__ZN7MyClass9set_myVarEi .local _ZStL8__ioinit .comm _ZStL8__ioinit,1,1 .hidden __dso_handle .ident "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1" .section .note.GNU-stack,"",@progbits 

Como puede ver claramente, el archivo de ensamblaje resultante es mucho más grande en el archivo C ++ que en el archivo C. Incluso si eliminas todas las otras cosas y simplemente comparas la C "main" con la C ++ "main", hay muchas cosas extra.

K&R significa que la mayoría de las expresiones en C (significado técnico) se asignan a una o unas pocas instrucciones de ensamblaje, no a una llamada de función a una biblioteca de soporte. Las excepciones habituales son la división de enteros en architectures sin una instrucción de div hardware, o un punto flotante en máquinas sin FPU.

Hay una cita:

C combina la flexibilidad y el poder del lenguaje ensamblador con la facilidad de uso del lenguaje ensamblador.

( Encontrado aquí . Pensé que recordaba una variación diferente, como “la velocidad del lenguaje ensamblador con la conveniencia y expresividad del lenguaje ensamblador”.)

long int suele ser del mismo ancho que los registros de la máquina nativa.

Algunos lenguajes de nivel superior definen el ancho exacto de sus tipos de datos, y las implementaciones en todas las máquinas deben funcionar igual. Aunque no C

Si desea trabajar con entradas de 128 bits en x86-64, o en el caso general BigInteger de tamaño arbitrario, necesita una biblioteca de funciones para ello. Todas las CPUs ahora usan el complemento 2s como la representación binaria de enteros negativos, pero incluso ese no fue el caso cuando se diseñó C. (Es por eso que algunas cosas que darían resultados diferentes en máquinas que no sean del complemento 2s no están definidas técnicamente en los estándares de C).

Los punteros C a datos o funciones funcionan de la misma manera que las direcciones de ensamblaje.

Si quieres referencias recontadas, debes hacerlo tú mismo. Si desea funciones de miembro virtual de c ++ que llaman a una función diferente dependiendo del tipo de objeto al que apunta su puntero, el comstackdor de C ++ debe generar mucho más que una simple instrucción de call con una dirección fija.

Las cuerdas son solo arreglos

Fuera de las funciones de la biblioteca, las únicas operaciones de cadena proporcionadas son leer / escribir un carácter. Sin concat, sin subcadena, sin búsqueda. (Las cadenas se almacenan como matrices terminadas en nulo ( '\0' ) con enteros de 8 bits, no con puntero + longitud, por lo que para obtener una subcadena tendrías que escribir un nulo en la cadena original.)

Las CPU a veces tienen instrucciones diseñadas para ser utilizadas por una función de búsqueda de cadenas, pero aún así generalmente procesan un byte por instrucción ejecutada, en un bucle. (o con el prefijo de representación x86. Tal vez si C se diseñó en x86, la búsqueda o comparación de cadenas sería una operación nativa, en lugar de una llamada a la función de biblioteca).

Muchas otras respuestas dan ejemplos de cosas que no son compatibles de forma nativa, como el manejo de excepciones, tablas hash, listas. La filosofía de diseño de K&R es la razón por la que C no tiene ninguno de estos de forma nativa.

El lenguaje ensamblador de un proceso generalmente trata con saltos (ir a), sentencias, sentencias de movimiento, artritis binaria (XOR, NAND, AND OR, etc.), campos de memoria (o dirección). Categoriza la memoria en dos tipos, instrucción y datos. Eso es sobre todo lo que es un lenguaje ensamblador (estoy seguro de que los progtwigdores de ensamblados argumentarán que hay más que eso, pero se reduce a esto en general). C se parece mucho a esta simplicidad.

C es ensamblar lo que el álgebra es aritmética.

C encapsula los conceptos básicos de ensamblaje (el lenguaje del procesador). Es probable que sea una statement más verdadera que “Porque la mayoría de las computadoras admiten los tipos de datos y las estructuras de control provistas por C”

Cuidado con las comparaciones engañosas

  1. La statement se basa en la noción de una “biblioteca de tiempo de ejecución” , que en su mayoría ha pasado de moda, al menos para los principales idiomas de alto nivel. (Todavía es relevante para los sistemas integrados más pequeños). El tiempo de ejecución es el soporte mínimo que un progtwig en ese lenguaje requiere para ejecutarse cuando se usan solo construcciones integradas en el lenguaje (en lugar de llamar explícitamente a una función proporcionada por una biblioteca) .
  2. En contraste, los idiomas modernos tienden a no discriminar entre el tiempo de ejecución y la biblioteca estándar , ya que estos últimos suelen ser bastante extensos.
  3. En el momento del libro de K&R, C ni siquiera tenía una biblioteca estándar . Más bien, las bibliotecas de C disponibles diferían bastante entre los diferentes tipos de Unix.
  4. Para comprender la afirmación, no debe compararse con los idiomas con una biblioteca estándar (como Lua y Python que se mencionan en otras respuestas), sino con los idiomas con más construcciones integradas (como el LISP antiguo y el FORTRAN antiguo mencionados en otros respuestas). Otros ejemplos serían BASIC (interactivo, como LISP) o PASCAL (comstackdo, como FORTRAN), que tienen (entre otras cosas) características de entrada / salida integradas en el propio idioma.
  5. En contraste, no hay una manera estándar de obtener los resultados de cómputo de un progtwig en C que usa solo el tiempo de ejecución, no cualquier biblioteca.

¿Hay un ejemplo de un tipo de datos o una estructura de control que no es compatible directamente con una computadora?

Todos los tipos de datos fundamentales y sus operaciones en el lenguaje C se pueden implementar mediante una o unas pocas instrucciones en el lenguaje de la máquina sin hacer un bucle; están directamente soportadas por la CPU (prácticamente todas).

Varios tipos de datos populares y sus operaciones requieren docenas de instrucciones en lenguaje de máquina, o requieren iteración de algún ciclo de tiempo de ejecución, o ambos.

Muchos idiomas tienen una syntax abreviada especial para tales tipos y sus operaciones; el uso de dichos tipos de datos en C generalmente requiere escribir mucho más código.

Tales tipos de datos y operaciones incluyen:

  • Manipulación de cadena de texto de longitud arbitraria: concatenación, subcadena, asignación de una cadena nueva a una variable inicializada con alguna otra cadena, etc. (‘s = “Hello World!”; s = (s + s) [2: -2] ‘en Python)
  • conjuntos
  • objetos con destructores virtuales nesteds, como en C ++ y cualquier otro lenguaje de progtwigción orientado a objetos
  • Matriz 2D de multiplicación y división; resolviendo sistemas lineales (“C = B / A; x = A \ b” en MATLAB y muchos lenguajes de progtwigción de matriz)
  • expresiones regulares
  • matrices de longitud variable: en particular, agregar un elemento al final de la matriz, lo que (a veces) requiere asignar más memoria.
  • leer el valor de las variables que cambian de tipo en el tiempo de ejecución – a veces es un flotante, otras veces es una cadena
  • matrices asociativas (a menudo llamadas “mapas” o “diccionarios”)
  • liza
  • relaciones (“(+ 1/3 2/7)” da “13/21” en Lisp )
  • aritmética de precisión arbitraria (a menudo llamada “bignums”)
  • conversión de datos en una representación imprimible (el método “.tostring” en JavaScript)
  • saturación de números de punto fijo (a menudo utilizados en progtwigs C incrustados)
  • evaluar una cadena escrita en el tiempo de ejecución como si fuera una expresión (“eval ()” en muchos lenguajes de progtwigción).

Todas estas operaciones requieren docenas de instrucciones en lenguaje de máquina o requieren iterar algún ciclo de tiempo de ejecución en casi todos los procesadores.

Algunas estructuras de control populares que también requieren docenas de instrucciones en lenguaje de máquina o bucles incluyen:

  • cierres
  • continuaciones
  • excepciones
  • evaluación perezosa

Ya sea que esté escrito en C o en otro idioma, cuando un progtwig manipula dichos tipos de datos, la CPU debe ejecutar las instrucciones necesarias para manipular esos tipos de datos. Esas instrucciones a menudo están contenidas en una “biblioteca”. Cada lenguaje de progtwigción, incluso C, tiene una “biblioteca de tiempo de ejecución” para cada plataforma que se incluye de forma predeterminada en cada ejecutable.

La mayoría de las personas que escriben comstackdores ponen las instrucciones para manipular todos los tipos de datos que están “incorporados en el lenguaje” en su biblioteca de tiempo de ejecución. Debido a que C no tiene ninguno de los tipos de datos anteriores y las operaciones y estructuras de control integradas en el lenguaje, ninguno de ellos está incluido en la biblioteca de tiempo de ejecución de C, lo que hace que la biblioteca de tiempo de ejecución de C sea más pequeña que la biblioteca de tiempo de ejecución de C. biblioteca de tiempos de otros lenguajes de progtwigción que tienen más de lo anterior incorporado al lenguaje.

Cuando un progtwigdor desea un progtwig (en C o cualquier otro lenguaje de su elección) para manipular otros tipos de datos que no están “integrados en el lenguaje”, ese progtwigdor generalmente le dice al comstackdor que incluya bibliotecas adicionales con ese progtwig, o algunas veces (para “evitar dependencias”) escribe otra implementación más de esas operaciones directamente en el progtwig.

¿Cuáles son los tipos de datos incorporados en C ? Son cosas como int , char , * int , float , arrays, etc … Estos tipos de datos son entendidos por la CPU. La CPU sabe cómo trabajar con matrices, cómo desreferenciar los punteros y cómo realizar la aritmética en los punteros, enteros y números de punto flotante.

Pero cuando va a lenguajes de progtwigción de nivel superior, ha construido tipos de datos abstractos y construcciones más complejas. Por ejemplo, observe la amplia gama de clases incorporadas en el lenguaje de progtwigción C ++. La CPU no comprende clases, objetos o tipos de datos abstractos, por lo que el tiempo de ejecución de C ++ cierra la brecha entre la CPU y el idioma. Estos son ejemplos de tipos de datos que no son compatibles directamente con la mayoría de las computadoras.

Depende de la computadora. En el PDP-11, donde se inventó C, el soporte long fue deficiente (había un módulo complementario opcional que podía comprar que admitía algunas operaciones de 32 bits, pero no todas). Lo mismo es cierto en varios grados en cualquier sistema de 16 bits, incluida la PC original de IBM. Y también para operaciones de 64 bits en máquinas de 32 bits o en progtwigs de 32 bits, aunque el lenguaje C en el momento del libro K&R no tenía ninguna operación de 64 bits. Y, por supuesto, ha habido muchos sistemas a lo largo de los años 80 y 90 [incluidos los procesadores 386 y algunos 486], e incluso algunos sistemas integrados en la actualidad, que no admitían directamente la aritmética de punto flotante ( float o double ).

Para un ejemplo más exótico, algunas architectures de computadora solo admiten punteros “orientados a palabras” (que apuntan a un entero de dos bytes o de cuatro bytes en la memoria), y los punteros de bytes ( char * o void * ) tuvieron que implementarse agregando un campo de desplazamiento extra. Esta pregunta entra en algunos detalles sobre tales sistemas.

Las funciones de “biblioteca de tiempo de ejecución” a las que hace referencia no son las que verá en el manual, sino funciones como estas, en una biblioteca de tiempo de ejecución del comstackdor moderno , que se utilizan para implementar las operaciones de tipo básico que no son compatibles con la máquina . La biblioteca de tiempo de ejecución a la que se referían K&R se puede encontrar en el sitio web de The Unix Heritage Society . Puede ver funciones como ldiv (distinta de la función C del mismo nombre, que no existía en ese momento) que se usa para implementar la división de valores de 32 bits, que el PDP-11 no era compatible incluso con el complemento, y csv (y cret también en csv.c) que guarda y restaura registros en la stack para administrar llamadas y devoluciones desde funciones.

Probablemente también se referían a su elección de no admitir muchos tipos de datos que no son compatibles directamente con la máquina subyacente, a diferencia de otros lenguajes contemporáneos como FORTRAN, que tenían una semántica de matriz que no se asignaba tan bien al soporte de puntero subyacente de la CPU como Arrays de C. El hecho de que los arrays C siempre están indexados a cero y siempre tienen un tamaño conocido en todos los rangos, pero el primero significa que no hay necesidad de almacenar los rangos de índice o tamaños de los arrays, y no es necesario tener funciones de biblioteca en tiempo de ejecución para acceder a ellos. el comstackdor puede simplemente codificar la aritmética del puntero necesario.

La statement simplemente significa que los datos y las estructuras de control en C están orientadas a la máquina.

Hay dos aspectos a considerar aquí. Una es que el lenguaje C tiene una definición (estándar ISO) que permite la latitud en la forma en que se definen los tipos de datos. Esto significa que las implementaciones en lenguaje C se adaptan a la máquina . Los tipos de datos de un comstackdor de C coinciden con lo que está disponible en la máquina a la que se dirige el comstackdor, porque el idioma tiene latitud para eso. Si una máquina tiene un tamaño de palabra inusual, como 36 bits, entonces se puede hacer que el tipo int o long se ajuste a eso. Los progtwigs que asumen que int es exactamente 32 bits se romperán.

En segundo lugar, debido a tales problemas de portabilidad, hay un segundo efecto. En cierto modo, la statement en el K&R se ha convertido en una especie de profecía autocumplida , o tal vez a la inversa. Es decir, los implementadores de nuevos procesadores son conscientes de la gran necesidad de admitir comstackdores de C, y saben que existe una gran cantidad de código C que asume que “todos los procesadores parecen un 80386”. Las architectures están diseñadas con C en mente: y no solo con C en mente, sino también con conceptos erróneos comunes acerca de la portabilidad de C en mente. Simplemente no puede introducir una máquina con bytes de 9 bits o lo que sea para uso general. Los progtwigs que suponen que el tipo char tiene exactamente 8 bits de ancho se interrumpirán. Solo algunos progtwigs escritos por expertos en portabilidad seguirán funcionando: probablemente no lo suficiente como para reunir un sistema completo con una cadena de herramientas, kernel, espacio para usuarios y aplicaciones útiles, con un esfuerzo razonable. En otras palabras, los tipos C se parecen a lo que está disponible en el hardware porque se diseñó para que se pareciera a otro hardware para el que se escribieron muchos progtwigs C no portátiles.

¿Hay un ejemplo de un tipo de datos o una estructura de control que no es compatible directamente con una computadora?

Tipos de datos que no se admiten directamente en muchos lenguajes de máquina: entero de precisión múltiple; lista enlazada; tabla de picadillo; cadena de caracteres.

Estructuras de control no compatibles directamente en la mayoría de los lenguajes de máquina: continuación de primera clase; coroutine / hilo; generador; manejo de excepciones.

Todo esto requiere un considerable código de soporte en tiempo de ejecución creado con numerosas instrucciones de propósito general y más tipos de datos elementales.

C tiene algunos tipos de datos estándar que no son compatibles con algunas máquinas. Desde C99, C tiene números complejos. Están hechos de dos valores de punto flotante y están diseñados para funcionar con rutinas de biblioteca. Algunas máquinas no tienen ninguna unidad de punto flotante.

Con respecto a algunos tipos de datos, no está claro. Si una máquina tiene soporte para direccionar la memoria usando un registro como una dirección base y otro como un desplazamiento escalado, ¿eso significa que las matrices son un tipo de datos directamente compatible?

Además, hablando de punto flotante, existe una estandarización: punto flotante IEEE 754. La razón por la que su comstackdor de C tiene un double que concuerda con el formato de punto flotante admitido por el procesador no es solo porque los dos se hicieron de acuerdo, sino porque existe un estándar independiente para esa representación.

Cosas como

  • Listas utilizadas en casi todos los lenguajes funcionales.

  • Excepciones .

  • Arrays asociativos (Mapas) – incluidos en, por ejemplo, PHP y Perl.

  • Recogida de basura .

  • Tipos de datos / estructuras de control incluidos en muchos idiomas, pero no soportados directamente por la CPU.

Admitido directamente debe entenderse como una asignación eficiente al conjunto de instrucciones del procesador.

  • El soporte directo para los tipos de enteros es la regla, excepto para el largo (puede requerir rutinas aritméticas extendidas) y los tamaños cortos (pueden requerir enmascaramiento).

  • El soporte directo para los tipos de punto flotante requiere una FPU para estar disponible.

  • El soporte directo para campos de bits es excepcional.

  • Las estructuras y los arreglos requieren el cálculo de la dirección, que se admite directamente hasta cierto punto.

  • Los punteros siempre son compatibles directamente a través de direccionamiento indirecto.

  • goto / if / while / for / do son soportados directamente por twigs incondicionales / condicionales.

  • El interruptor puede ser soportado directamente cuando se aplica una tabla de salto.

  • Las llamadas de función son compatibles directamente por medio de las funciones de stack.