Lista de plataformas compatibles con el estándar C

12 minutos de lectura

avatar de usuario
tity

¿Alguien sabe de alguna plataforma compatible con el estándar C, para la cual todavía hay trabajo de desarrollo activo, pero que son:

  • no complemento a 2 o
  • el ancho entero no es 32 bits o 64 bits o
  • algunos tipos de enteros tienen bits de relleno o
  • si trabajó en una máquina de complemento a 2, el patrón de bits con el bit de signo 1 y todos los bits de valor cero no es un número negativo válido o
  • la conversión de enteros de firmados a sin firmar (y viceversa) no se realiza mediante la copia literal de patrones de bits o
  • el desplazamiento a la derecha de un entero no es un desplazamiento aritmético o
  • el número de bits de valor en un tipo sin signo no es el número de bits de valor en el tipo con signo correspondiente + 1 o
  • la conversión de un tipo int más amplio a un tipo más pequeño no se realiza mediante el truncamiento de los bits más a la izquierda que no encajarían

EDITAR: Alternativamente, si hay plataformas en el período de 1995 a 1998 que influyeron en la decisión de C99 de incluir lo anterior, pero que fueron descontinuadas, también estaría interesado en ellas.

EDITAR: La justificación de C tiene esto que decir sobre los bits de relleno:

Los bits de relleno son accesibles para el usuario en un tipo de entero sin signo. Por ejemplo, suponga que una máquina usa un par de cortos de 16 bits (cada uno con su propio bit de signo) para formar un int de 32 bits y el bit de signo del corto inferior se ignora cuando se usa en este int de 32 bits. Luego, como un int con signo de 32 bits, hay un bit de relleno (en medio de los 32 bits) que se ignora al determinar el valor del int con signo de 32 bits. Pero, si este elemento de 32 bits se trata como un int sin firmar de 32 bits, entonces ese bit de relleno es visible para el programa del usuario. Se le dijo al comité C que hay una máquina que funciona de esta manera, y esa es una de las razones por las que se agregaron bits de relleno a C99.

Las notas al pie 44 y 45 mencionan que los bits de paridad pueden ser bits de relleno. El comité no conoce ninguna máquina con bits de paridad accesibles para el usuario dentro de un número entero. Por lo tanto, el comité no tiene conocimiento de ninguna máquina que trate los bits de paridad como bits de relleno.

Entonces, otra pregunta es, ¿cuál es esa máquina que mencionó C99?

EDITAR: Parece que C99 estaba considerando eliminar el soporte para el complemento de 1 y la magnitud firmada: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n868.htm http://www.open-std.org/jtc1/sc22/wg14/www/docs/n873.htm (busque 6.2.6.2)

  • Parece una especie de pregunta de trivia. ¿Para qué sirve? ¿Tarea?

    – RojoX

    4 de noviembre de 2011 a las 10:28

  • Además, sospecho que el comité C es (deliberadamente) demasiado optimista acerca de las personas que actualizan compiladores para sistemas heredados. Por ejemplo, consulte stackoverflow.com/questions/161797/… — Dudo que los sistemas de complemento de 1 enumerados allí tengan compiladores C99 mantenidos activamente, pero sospecho que el comité C quiere que sea posible aunque es poco probable que realmente suceda (y, por lo tanto, no cumple con los criterios establecidos).

    –Steve Jessop

    4 de noviembre de 2011 a las 11:18


  • Nunca programé tales cosas, pero debe buscar las rarezas en el lado de los procesadores integrados y otras arquitecturas especiales. Por cierto, deberías haber enumerado CHARBIT != 8 a tu lista de cosas que rara vez ves en el mundo real hoy en día.

    – Jens Gusted

    4 de noviembre de 2011 a las 14:05

  • @Jens: CHAR_BIT != 8 aunque es demasiado fácil. Hay DSP modernos reales que tienen bytes de gran tamaño, por lo que es fácil imaginar que el comité C querría que C fuera aplicable allí, sin el escritor del compilador necesita crear una representación de un “puntero C” que se dirija a una unidad más pequeña que las direcciones naturales del hardware.

    –Steve Jessop

    4 de noviembre de 2011 a las 16:00


  • Creo que en tu lista de deseos olvidaste un caso especial que hace que al menos 3, 6 sean triviales: _Bool. Se menciona explícitamente entre los tipos enteros sin signo. En muchas arquitecturas el CHAR_BIT-1 los bits superiores son bits de relleno y la conversión a ese tipo no es un truncamiento. Pero esto probablemente no sea lo que buscas.

    – Jens Gusted

    7 de noviembre de 2011 a las 12:48

Recientemente trabajé en una empresa que todavía usaba una versión del PDP-10 y un puerto de GCC para esa plataforma. Los 10 que usamos tenían algunos de los atributos que enumeras:

  • Los números enteros no son de 32 o 64 bits, tienen 36 bits de ancho.
  • Los bits de relleno se utilizan para algunas representaciones. Para enteros de precisión extendida (por ejemplo, de tipo long long), la representación subyacente era de 72 bits en la que cada una de las palabras de 36 bits tenía un bit de signo.

Además de los atributos inusuales anteriores, estaba el problema de que la máquina tenía varios mecanismos de direccionamiento de bytes diferentes. Los bytes con anchos en el rango de 6 a 12 bits de ancho podrían direccionarse usando bits especiales en la propia dirección que indicaban qué ancho y alineación de palabra se estaba usando. Para representar un char*, se podría usar una representación que abordaría bytes de 8 bits, todos los cuales estaban alineados a la izquierda en la palabra, dejando 4 bits en cada palabra de 36 bits que no estaban direccionados en absoluto. Alternativamente, se podrían usar bytes de 9 bits que encajarían uniformemente en la palabra de 36 bits. Ambos enfoques tenían problemas de portabilidad, pero en el momento en que me fui, se consideró más práctico usar los bytes de 8 bits debido a la interacción con las redes TCP/IP y los dispositivos estándar que a menudo piensan en términos de 16, 24 o 32. -campos de bits que también tienen una estructura subyacente de bytes de 8 bits.

Por lo que sé, esta plataforma todavía se usa en productos en el campo, y hay un desarrollador de compiladores en esta empresa que mantiene actualizadas versiones relativamente recientes de GCC para permitir un mayor desarrollo de C en esta plataforma.

avatar de usuario
han

Debe tenerse en cuenta que no puede confiar en un comportamiento indefinido, incluso en plataformas de uso común, porque los compiladores de optimización modernos realizan transformaciones de programas que solo conservan el comportamiento definido.

En particular, no puede confiar en que la aritmética del complemento a dos le proporcione INT_MAX+1 == INT_MIN. Por ejemplo, gcc 4.6.0 optimiza lo siguiente en un bucle infinito:

#include <stdio.h>
int main() {
     int i = 0;
     while (i++ >= 0)
          puts(".");
     return 0;
}

EDITAR: Mira aquí para obtener más información sobre el desbordamiento firmado y las optimizaciones de GCC.

  • @JonathanLeffler: originalmente publiqué el código sin el operador ++, pero lo arreglé casi de inmediato. ¿Su comentario se basa en la versión anterior? La versión fija del código termina si usa un compilador que admita la aritmética de complemento a dos (en la que 0x7fffffff + 1 == -0x80000000 en una máquina de 32 bits).

    – han

    5 de noviembre de 2011 a las 9:51

  • bien – el ++ hace que mi comentario sea inexacto… Lo quitaré. (Sí, vi la versión sin el ++posiblemente porque no actualicé antes de comentar).

    –Jonathan Leffler

    6 de noviembre de 2011 a las 2:12

  • @han: Interesante. ¿Conoces más detalles sobre este caso en particular?

    – undur_gongor

    7 de noviembre de 2011 a las 8:29

  • @undur_gongor: hay una buena descripción general específica de GCC aquí. La opción de GCC -fwrapv fuerza la aritmética del complemento a 2 y, en el compilador IBM XL C/C++, la optimización anterior está desactivada por -qstrict_induction. Los desarrolladores de GCC también sostienen que el compilador de Intel realiza optimizaciones de bucle similares, pero no he encontrado una opción de línea de comando equivalente para él.

    – han

    7 de noviembre de 2011 a las 16:41

  • @han: Muchas gracias, desearía poder votar más de una vez. Debes agregar el enlace a tu respuesta.

    – undur_gongor

    7 de noviembre de 2011 a las 17:16

Hace aproximadamente una década, tuvimos que portar nuestra base de datos integrada en C a un procesador DSP que resultó ser el procesador principal de un estéreo de automóvil. Era una máquina de 24 bits, de la peor manera: sizeof(char) == sizeof(int) == sizeof(void*) == 1, que era de 24 bits. Llamamos a la rama que se ocupaba de este puerto “infierno de 24 bits”.

Desde entonces, migramos nuestra biblioteca a muchas plataformas, pero ninguna tan extraña como esa. Es posible que todavía estén disponibles (los chips DSP de 24 bits baratos son aún más baratos ahora), que se encuentran en dispositivos de bajo costo donde la facilidad de programación es un segundo distante después de una baja lista de materiales (BOM). Ahora que lo pienso, creo que nos encontramos con una máquina en la que un desplazamiento a la derecha de un entero sin signo no insertaba necesariamente cero bits. Aun así, las reglas aritméticas altamente no estándar en una plataforma garantizan una migración de software desafiante y propensa a errores, lo que aumenta drásticamente los costos de desarrollo de software. En algún momento prevalece la cordura y se observan las normas.

Sospecho que gran parte de la motivación para la presencia de estas reglas en C99 es su presencia en C89 y versiones anteriores del lenguaje. No olvide que cuando se inventó C, las computadoras eran mucho más diversas de lo que son hoy. Los diseños de procesador de “rebanada de bits” estaban disponibles en los que podía agregar tantos bits como quisiera a su procesador simplemente agregando chips. Y antes de C, tenía que codificar en lenguaje ensamblador o preocuparse por exactamente dónde residiría su código en la RAM, etc.

C fue un gran paso adelante en términos de portabilidad, pero tenía que abarcar una amplia gama de sistemas, de ahí las reglas muy generales. 20 años más tarde, cuando apareció Java, tuvo el beneficio de la historia para permitirle declarar por adelantado cuán grandes debían ser los tipos primitivos, lo que hace que todo sea mucho más fácil, siempre que las elecciones de Java sean sólidas.

Sé que en su mayoría está preguntando sobre números enteros, pero me he encontrado con algunas rarezas cuando se trata de punteros. Las primeras computadoras Macintosh tenían procesadores de 32 bits (Motorola 68000), pero solo buses de memoria de 24 bits. Por lo tanto, 0x00123456 y 0xFF123456 se referían a la misma celda de memoria, porque el procesador cortó los 8 bits superiores al acceder a la RAM. Los ingenieros de Apple usaron estos bits para almacenar metadatos sobre la memoria a la que apuntaba el puntero. Por lo tanto, al comparar punteros, primero había que enmascarar los bits superiores. Y no me hagas empezar con el arquitecturas de memoria segmentada del x86. 🙂

Ya que estamos en este tema, eche un vistazo a la MISRA estándar de codificación, que es favorecido por los fabricantes de automóviles que necesitan la máxima portabilidad y seguridad. también mira Delicia de hacker por Henry S. Warren, que tiene toneladas de trucos útiles.

Mis dos centavos. Por favor, no culpes mucho, esto es desde mi experiencia, no soy un teórico:

  • no complemento a 2

Todos de las CPU existentes son complemento a 2

  • el ancho entero no es 32 bits o 64 bits

También hay arquitecturas de 8 y 16 bits. Los microcontroladores AVR de 8 bits son un buen ejemplo.

  • algunos tipos de enteros tienen bits de relleno

no soy consciente de ninguna sistema, que almohadillas números enteros Números flotantes – es una historia diferente.

  • si trabajó en una máquina de complemento a 2, el patrón de bits con el bit de signo 1 y todos los bits de valor cero no es un número negativo válido
  • la conversión de enteros de firmados a sin firmar (y viceversa) no se realiza mediante la copia textual de patrones de bits
  • el desplazamiento a la derecha de un entero no es un desplazamiento aritmético
  • el número de bits de valor en un tipo sin signo no es el número de bits de valor en el tipo con signo correspondiente + 1
  • la conversión de un tipo int más amplio a un tipo más pequeño no se realiza mediante el truncamiento de los bits más a la izquierda que no encajarían

Todo lo anterior: no tengo conocimiento de ninguno, y asumo que no existe tal máquina.

Incluso si estas máquinas son antiguas, todavía hay una programación comunitaria activa para PDP-8, la mayoría, pero no todas, usan simulaciones: PDP-8 como ejemplo. ¡Y esta máquina, AFAIK, usa números enteros de 12 bits!

avatar de usuario
Un tipo programador

los cc65 El compilador para Commodore C64 parece haber tenido alguna actualización el año pasado.

avatar de usuario
Basile Starynkevitch

Un viejo adagio (olvidé la atribución) dice que

no existe el código portátil

Pero solo que hay algún código que ha sido portado.

No debe preocuparse por escribir código portátil, debe preocuparse por escribir código que sea fácil de trasladar a otras plataformas.

Además, usar solo el estándar C no te da muchas cosas útiles. Los estándares Posix le brindan mucho más.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad