2010-02-20 13 views
12

Para un proyecto en la universidad, necesito extender una aplicación C existente, que al final se ejecutará en una amplia variedad de sistemas unix comerciales y no comerciales (FreeBSD, Solaris, AIX, etc.).Escribir un programa C portátil - ¿qué cosas considerar?

¿Qué cosas tengo que considerar cuando quiero escribir un programa C que es más portátil?

+6

Considere http://stackoverflow.com/questions/1257923/why-is-it-difficult-to-write-portable-c-programs-closed y http://stackoverflow.com/questions/61499/making- código portátil y, de hecho, gran parte de http://stackoverflow.com/search?q=[c]+portable. – dmckee

Respuesta

21

El mejor consejo que puedo dar, es pasar a una plataforma diferente cada día, probando sobre la marcha.
Esto hará que las diferencias de la plataforma sobresalgan como un pulgar dolorido, y le enseñará los problemas de portabilidad al mismo tiempo.

Si se guardan las pruebas de plataforma cruzada para el final, se producirá un error.

Aparte de eso

  • tamaños enteros pueden variar.
  • números de coma flotante pueden representarse de manera diferente.
  • enteros pueden tener endianismo diferente.
  • Las opciones de compilación pueden variar.
  • incluir nombres de archivos puede variar.
  • implementaciones de campo de bits variarán.

Por lo general, es una buena idea establecer su nivel de advertencia del compilador hasta lo más alto posible, para ver el tipo de cosas que el compilador puede quejarse.

+3

+1 para niveles altos de advertencia del compilador. –

+0

Si bien este es un consejo muy acertado (+1), hablar con un principiante, ¿diría usted que esto se aplica principalmente a C más avanzado, y no tanto a lo que la mayoría de la gente reconocería como código "directo", por ejemplo, código que no importa si los enteros son de 2 bytes o 200 bytes? Quiero decir, 'Hello World' es' Hello World', ¿verdad? –

+0

No. Lo reclamo en general. En el trabajo, estamos transfiriendo el código a una nueva versión de g ++. El código que se estaba compilando anteriormente no pudo compilarse, debido a que falta un archivo de inclusión. Mantenga los niveles de advertencia altos, y use múltiples compiladores y plataformas múltiples tanto como pueda. Por cierto, estamos utilizando aplicaciones CRUD/Console en nuestro dominio. – EvilTeach

3

Es una lista muy larga. Lo mejor que puedes hacer es leer ejemplos. El source of perl, por ejemplo. Si nos fijamos en el origen de perl, verá un gigantesco proceso de construcción de un archivo de encabezado que trata con aproximadamente 50 problemas de plataforma.

Léelo y llorar, o pedir prestado.

+3

Cuando leo perl, lloro. – Seth

+2

Ese es un problema completamente diferente. Esta es la fuente de perl. Debería hacerte aullar. – bmargulies

1

La lista puede ser larga, pero no es tan larga como para Windows y MSDOS. Lo cual es común con muchas utilidades.

La técnica habitual es separar los módulos del algoritmo central de los que tratan con el sistema operativo, básicamente una estrategia de abstracción en capas.

Diferenciar entre varios sabores de Unix es bastante simple en comparación. O bien se adhieren a las características, todos usan los mismos nombres de RTL, o mire la convención de la mayoría para las plataformas compatibles y #ifdef en las excepciones.

4
  1. Utilice al menos dos compiladores.
  2. Tienen un sistema de compilación continuo en su lugar, que preferiblemente se basa en las distintas plataformas de destino.
  3. Si no necesita trabajar a muy bajo nivel, intente utilizar alguna biblioteca que proporcione abstracción. Es poco probable que no encuentre bibliotecas de terceros que proporcionen una buena abstracción para las cosas que necesita. Por ejemplo, para la red y la comunicación, hay ACE. Boost (por ejemplo, el sistema de archivos) también se transporta a varias plataformas. Estas son bibliotecas C++, pero también puede haber otras bibliotecas C (como curl).
  4. Si tiene que trabajar en el nivel bajo, tenga en cuenta que las plataformas ocasionalmente tienen un comportamiento diferente incluso en cosas como posix donde se supone que tienen el mismo comportamiento.Puede echarle un vistazo al código fuente de las bibliotecas de arriba.
+0

+1 por la idea de usar más de un compilador. ¿Hay alguna herramienta que pueda automatizar esto de alguna manera? Supongo que técnicamente, usar un Makefile e intercambiar el valor de $ (CC) y $ (FLAGS) podría hacerlo, pero sería genial si hubiera un daemon o algo que pudiera verificar esto en el fondo ... – Miguel

+0

Uso cmake o alguna otra "herramienta de compilación portátil" (consulte, por ejemplo, http://stackoverflow.com/questions/3349956/portable-c-build-system). Para ver un ejemplo, vea los archivos cmake de mi proyecto (estos son archivos .txt en http://crackpot.svn.sourceforge.net/viewvc/crackpot/trunk/crackpot/ y su directorio base). –

2

Una cuestión particular que puede que tenga que mantenerse al tanto de (por ejemplo, si se espera que los archivos de datos para trabajar en todas las plataformas) es endianness.

Los números se representan de forma diferente en el nivel binario en diferentes arquitecturas. Los sistemas Big-Endian piden los bytes más significativos primero y los sistemas little-endian piden primero el byte menos significativo.

Si escribe algunos datos sin procesar en un archivo en una endianness y luego vuelve a leer ese archivo en un sistema con una endianidad diferente, obviamente tendrá problemas.

Debería poder obtener el endianness en tiempo de compilación en la mayoría de los sistemas desde sys/param.h. Si necesita detectarlo en tiempo de ejecución, un método es usar una unión de int y char, luego establecer char en 1 y ver qué valor tiene el int.

1

Consulte continuamente los estándares POSIX para cualquier función de biblioteca que utilice. Las partes del estándar son ambiguas y algunos sistemas devuelven diferentes estilos de códigos de error. Esto te ayudará a encontrar de forma proactiva esos errores de implementación ligeramente difíciles de encontrar.

6

Solía ​​escribir utilidades C que luego admitiría en arquitecturas de 16 bits a 64 bits, incluidas algunas máquinas de 60 bits. Incluían al menos tres variedades de "endianness", diferentes formatos de punto flotante, diferentes codificaciones de caracteres y diferentes sistemas operativos (aunque Unix predominaba).

  1. Mantente tan cerca de la C estándar como puedas. Para funciones/bibliotecas que no forman parte del estándar, use una base de código ampliamente compatible como la que puede encontrar. Por ejemplo, para redes, use la interfaz de socket BSD, con uso nulo o mínimo de opciones de socket de bajo nivel, señalización fuera de banda, etc. Para admitir una gran cantidad de plataformas dispares con un personal mínimo, deberá permanecer con funciones normales de vainilla.
  2. Sea muy consciente de lo que está garantizado por el estándar, vicepresidente, lo que es el comportamiento de implementación típico. Por ejemplo, los punteros no son necesariamente del mismo tamaño que los enteros, y los punteros a diferentes tipos de datos pueden tener diferentes longitudes. Si debe hacer supuestos dependientes de la implementación, documentarlos de manera exhaustiva. Lint, o --strict, o lo que sea que tu conjunto de herramientas de desarrollo tenga como equivalente, es de vital importancia aquí.
  3. Los archivos de encabezado son su amigo. Use implementaciones definidas macros y constantes. Use definiciones de encabezado y #ifdef para ayudar a aislar aquellas instancias en las que necesita cubrir una pequeña cantidad de alternativas.
  4. No asuma que la plataforma actual usa caracteres EBCDIC y enteros decimales empaquetados. Hay un buen número de ASCII, dos máquinas de complemento también. :-)

Con todo eso, si evita la tentación de escribir cosas varias veces y #ifdef partes importantes de código, encontrará que la codificación y las pruebas en plataformas dispares ayudan a encontrar errores más pronto. Terminará produciendo programas más disciplinados, comprensibles y mantenibles.

+2

+1 para el punto 4. –

+0

Y creo que la biblioteca estándar C es la misma en todos los sistemas * nix. Tanto para el 'estándar' ... – helpermethod

+0

La biblioteca C Standard es la misma. Muchos programas usan cosas fuera del estándar C, como la comunicación entre procesos. Además de eso, "más portátil" probablemente se extiende más allá del sistema Unix. – mpez0

Cuestiones relacionadas