2010-06-23 18 views
25

¿Cuáles son las cosas que debo tener en cuenta para escribir código portátil? Como soy un principiante en C++, quiero practicarlo desde el principio.Cómo escribir código portable en C++?

Gracias.

+2

Esto huele como una pregunta de Wiki comunitario. – bta

+4

@bta: ¿Por qué, exactamente? Si alguien dedica 30 minutos a escribir una buena respuesta a esta pregunta, ¿no merecen el representante cuando se sube la apuesta? – jalf

+1

¿Dónde quieres portarlo? hay un mundo de diferencias si planeas portarlo a diferentes sistemas operativos, diferentes arquitecturas, entonces hay una respuesta para cada puerto, por ejemplo, trabajando en 8 o incluso 16 bits pequeños sistemas integrados, debes evitar el uso de cualquiera de las bibliotecas recomendado aquí, entonces, ¿podría ser más específico? –

Respuesta

15
  • aprender a usar la biblioteca estándar
  • leer libros (. Ej this one)
  • cuando se tiene experiencia, aprender a usar boost
+4

Además, libros como estos: http: // stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list –

+2

Entonces, ¿cómo exactamente el impulso está relacionado con la portabilidad? – SigTerm

+6

@SigTerm: uno de los principales objetivos de diseño de boost es la portabilidad. funcionará en una amplia variedad de plataformas, y hace un buen trabajo de abstracción de las diferencias. Por ejemplo, las bibliotecas de subprocesos y las bibliotecas de sistemas de archivos funcionan de forma independiente de la plataforma. Algunas de estas cosas están incluidas en C++ 0x. – rmeador

4

Utilice los tipos de STL cuando sea posible. Tenga cuidado al usar tipos y API dependientes del sistema. Por ejemplo, no use tipos como UINT y DWORD en Windows.

Puede usar una biblioteca como refuerzo para que le sea más fácil escribir código portátil. Si necesita una GUI, considere usar un conjunto de herramientas multiplataforma como Qt.

A veces será necesario escribir código específico de la plataforma, y ​​en esos casos se puede hacer algo como esto:

#ifdef _WIN32 
#include <windows.h> 
#else 
#include <unistd.h> 
#endif 
5

Comentario programas de línea de comando para comenzar. Cuando esté listo, busque un juego de herramientas de ventana multiplataforma como Qt.

Si le interesa escribir código multilingüe, use una biblioteca Unicode de terceros, como ICU, en lugar de basarse en bibliotecas específicas de la plataforma.

+2

... Y si maneja el texto, preocúpese por lo multilingüe. –

+2

La UCI es un punto muy bueno ya que C++ no tiene un tipo de datos de cadena real (con reconocimiento de Unicode). En los sistemas tipo Unix 'std :: string' a menudo funciona, en Windows' std :: wstring' siempre funciona, pero para los programas realmente independientes del sistema operativo necesita un tipo de datos de cadena real como 'UnicodeString' de ICU. – Philipp

1

Para aprender, trate de evitar libros que se concentren en una implementación. En algunos casos, la introducción o un capítulo temprano le darán algunas instrucciones sobre cómo obtener o usar una implementación de idioma; si menciona más de una implementación, probablemente estés bien.

Obtenga un libro de consulta que sea independiente de la plataforma. Stroustrup's El lenguaje de programación C++ es una buena referencia, aunque no es un buen libro para que un principiante intente aprender de él. No confíe en referencias para una implementación dada. MSDN es útil, por ejemplo, pero su enfoque principal es cómo escribir programas de Windows usando Visual C++, no cómo escribir programas que se compilarán y ejecutarán en cualquier lugar.

Para escribir algo realmente útil, tendrá que ingresar en un código que no sea portátil. Trate de adquirir el hábito de separar el código de la interfaz de usuario de todo lo demás, ya que es donde tendrá la menor compatibilidad. Cuanto menos código tenga que cambiar entre plataformas, más portátil será su código.

2

El programador incauto es probable que entre en un montón de trampas, que podemos intentar categorizar. Pero déjame decirte primero: como un absoluto es imposible.

El problema es que incluso el código de conformidad estándar podría no ser portátil debido a un problema particular del compilador.

Ahora aquí están las principales categorías que puedo pensar en la parte superior de mi cabeza.

extensiones del compilador

Como por ejemplo el uso de variables de matrices:

void func(int const n) 
{ 
    int array[n]; 
} 

Esto no es estándar, pero muchos compiladores lo apoyan, sin embargo, porque es sólo práctico.

bibliotecas extensiones estándar

Muchas implementaciones de librerías estándar proporcionan una std::hash_map que nunca fue especificado. Si lo usa en su código, no es portátil.

La tendencia moderna es esconder esto en el espacio de nombres std::tr1 para que los programadores sepan que se trata de una extensión.

También tenga en cuenta que muchos definen typedef o macros que no son genéricos (por ejemplo PRETTY_FUNCTION). El estándar no especifica ninguna macro, y muy pocos typedef son.

plataforma específica

Por ejemplo, el tamaño y la alineación de int o double no se especifica en la norma. Si haces bit-twiddling y esperas que tenga 32 bits, estarás atornillado a las plataformas de 64 bits incluso sin cambiar tu compilador.

API de la plataforma

Nuestros programas están diseñados para ser compilado, y que a menudo están destinados a interactuar con el ordenador que se ejecutan en:

  • para acceder al hardware
  • para acceder al sistema de archivos
  • para acceder a la pantalla

Necesita encontrar API portátiles multiplataforma o hacer las suyas propias. Verifique algunas bibliotecas en la lista a continuación.

Bibliotecas

bibliotecas más bien escritos son en gran medida portátil, sólo asegúrese de que ellos apoyan:

  • los compiladores le interesa
  • las plataformas que le interesan

Buenas bibliotecas implican:

  • Apache (la colección de bibliotecas)
  • Boost
  • Qt (por gráfico)
  • UCI (para el manejo de Unicode)

Los otros que hay que revisar ... y que requiere tiempo.

No creo que haya una respuesta perfecta allí. Pero como la portabilidad perfecta no es posible, debe decidir qué compiladores y plataforma desea admitir.

Para la plataforma, debe comenzar con Windows y un sabor Linux. Para los compiladores, elija dos (con Comeau si puede pagarlo).

+0

Las matrices de longitud variable probablemente se admiten porque están en el estándar ISO C 99, no por razones de practicidad. – ninjalj

+2

Muchos compiladores no implementan C99 en absoluto (por ejemplo, MSVC). Las matrices de longitud variable no son C++. –

+0

De hecho, anhelo macros variadas y sin embargo no son C++ :( –

0

una buena idea es utilizar las llamadas al sistema POSIX. De esta forma, no tendrá que lidiar con diferentes formas de crear subprocesos o usar mutexes y señales.

el problema es que Windows no es exactamente compatible con POSIX, pero hay bibliotecas que implementan ciertas funciones POSIX, como éste: [1]: http://sourceware.org/pthreads-win32/

+3

Diría que el uso de llamadas al sistema POSIX es exactamente lo contrario del código portátil. En lugar de eso, utilice las bibliotecas de alto nivel como las mencionadas en el otro – Philipp

13

mantener el código específico de la plataforma independiente de código reutilizable, preferiblemente en un archivo diferente, pero al menos en una función diferente. Si comienza a tener #if WIN32 y #if CYGWIN y #if BSD en todas partes, tendrá una pesadilla de mantenimiento.

Luego, compile en al menos dos plataformas diferentes temprano y con frecuencia. Las opciones típicas son Visual C++ en Windows y gcc en Linux. Dado que ni las bibliotecas del sistema ni el compilador se comparten, se detectará el código no portátil antes de que se arraigue profundamente en su diseño.

+2

automatice sus compilaciones, usando algo como Hudson, que se compilará según el cronograma (hora/día/día/en CVS checkin, etc.) y correo electrónico si falla una compilación. Puede usar máquinas virtuales y buidl para, por ejemplo, Windows y Linux en una PC – Mawg

1

El código independiente del sistema operativo es sorprendentemente difícil de hacer en C++. Considere este ejemplo trivial:

#include <iostream> 
int main(int argc, char** argv) { 
    std::cout << argv[0] << std::endl; 
} 

Eso es perfectamente válida C++, todavía es no portátil, ya que no aceptará Unicode argumentos de línea de comandos en Windows. La versión correcta para Windows sería:

#include <iostream> 
int wmain(int argc, wchar_t** argv) { 
    std::wcout << argv[0] << std::endl; 
} 

Por supuesto que es nuevo no portátil, trabajando solamente en Windows y ser no estándar. De hecho, ni siquiera puede escribir una función portátil main() en C++ sin recurrir a la compilación condicional.

+1

wchar_t no tiene nada que ver con unicode. –

+0

Eso causará problemas en cualquier plataforma. Use 'std :: endl' en su lugar, lo que vacía el búfer y realmente produce algún resultado. No puedo comenzar a contar todas las preguntas Lo he visto en SO, que se reducía a personas que no usaban 'cout'. –

+1

@Alexandre: Correcto, C++ en sí mismo no sabe nada sobre cadenas o Unicode, sino porque W indows usa cadenas UTF-16 y 'wchar_t' siempre es un entero sin signo de 16 bits en Windows (de lo contrario, no se compilaría ningún programa), puede usar' wchar_t' si desea compatibilidad con Unicode en Windows. @Ben: Gracias, lo corregiré. – Philipp

2

Algunas pautas:

  1. mantener el final del negocio del código y la interfaz gráfica de usuario independiente.
  2. Evite el uso de muletas específicas del compilador (#pragma, etc.)
  3. Use expresiones convencionales que no modifiquen el comportamiento con el compilador/plataforma en lugar de lindos trucos de manipulación de bits.
  4. Si toca el hardware, pertenece a un controlador de dispositivo.
  5. Use encabezados de tipo de datos como types.h (uint32_t, etc.).
  6. Utilice una capa de abstracción del sistema operativo para que no llame directamente al sistema operativo.

A veces hay que sacrificar eficiencia y rendimiento para ganar portabilidad. Por ejemplo, si su código requiere acceder a los campos desde un búfer, siempre puede lanzar una estructura empaquetada al puntero del búfer. Pero eso es terriblemente no portátil. Por lo tanto, en su lugar, necesita utilizar punteros con nombre calculados con compensaciones, a veces con código de manejo de alineación de límites. No es bonito, pero es portátil. Afortunadamente, puedes ocultar muchas de esas cosas con un uso juicioso de las interfaces de clase.

No es necesario escribir todo el código de esa manera. Si diseña su aplicación de una manera muy modular con límites de responsabilidad bien definidos, entonces el 90-95% del código puede ser portátil sin dolor. Luego, solo aísle el 5-10% en un área muy localizada que debería personalizarse para una nueva plataforma.

1

Si puede, compile todo su código con al menos dos compiladores diferentes.

3

Otros dijeron que antes, pero aquí está mi opinión sobre ella:

1) ¿Necesita C++? No es el mejor lenguaje para escribir código portátil porque está cerca del metal desnudo. Java, Python, Perl, PHP o Javascript pueden ser mejores para ti.

2) Si necesita C++, no intente escribir un código completamente portátil, de todos modos es casi imposible. En su lugar, decida primero qué plataformas desea admitir. Por ejemplo: Linux, MacOS X, Windows

3) Asegúrese de probar su código continuamente en todas las plataformas seleccionadas. No solo cree en Windows y espere simplemente compilar una versión de Linux 'cuando esté listo'. Compila todas las plataformas a diario y asegúrate de seguir analizándolas en busca de problemas.

+1

Junto con el n. ° 2, generalmente es más fácil pasar de compilar en 2 plataformas a compilar en> 2, que ir del 1 al 2. Agregar una segunda plataforma lo ayudará a encontrar la mayoría de los problemas de portabilidad. – KeithB

+1

+1 para el artículo n. ° 1. C++ es una de las peores elecciones si desea portabilidad, casi cualquier otro idioma, incluso Bash o Visual Basic, es más portátil. – Philipp

+1

A veces estar más cerca de "lo básico" es más portátil que estar drogado, cuando escribo código para el sistema integrado, C sin bibliotecas es el lenguaje más portátil, ¿por qué? porque hay compiladores para cada plataforma y funciona en entornos pequeños, C++ es el siguiente, pero no hay compilador para cada micro, así que volveré a preguntar, depende de "¿A dónde quieres conectarlo?" –

11

¿Cuáles son las cosas que debo tener en cuenta para escribir código portátil?

  1. Guarde varios compiladores cerca, código de prueba regularmente en plataformas de destino. Si está haciendo un software multiplataforma para Windows Windows/Linux, manténgase cerca de mingw, visual studio express (es decir, "compilador de Microsoft") y una instalación de Linux con g ++ (o use la máquina virtual). Incluso si tu código es perfecto, el compilador podría tener algún tipo de peculiaridad inesperada. Por ejemplo, ciertas versiones del compilador ms tienen un límite en los tamaños de las constantes de cadena, que no tiene gcc.
  2. No confíe en los tamaños de los tipos estándar. Por ejemplo, en msvc sizeof (wchar_t) es de 2 bytes. En la instalación de Linux, puede ser de 4 bytes. Use sizeof (si lo necesita), o trate de evitar tener que usar el tamaño de cualquier tipo en su código. Y no debe suponer que el puntero tiene 4 bytes de tamaño (pasando el puntero de datos de usuario al escenario de llamada de API): tendrá 8 bytes en 64 bits.
  3. No utilice pragmas, macros y extensiones específicos del compilador. Por ejemplo, evite "#pragma una vez".
  4. No utilice extensiones a la biblioteca estándar (proporcionadas por el desarrollador del compilador). Esto es más aplicable a las funciones de la biblioteca C, sin embargo. Por ejemplo, el compilador de MS proporciona múltiples versiones "seguras" (como strcpy_s) de las rutinas estándar de estilo C. Que, por supuesto, no estará disponible en otras plataformas.
  5. Tenga mucho cuidado si decide usar rutinas estilo C (como sprintf) en código C++. (I saber que se supone que es una mala práctica, pero en algunos escenarios esto es útil) Tienen implementaciones ligeramente diferentes, extensiones y diferente número de parámetros. Por ejemplo, sprintf puede tener diferentes formatos adicionales que se implementan de manera diferente en diferentes plataformas. Por ejemplo, la última vez que comprobé que "% S" se comporta de forma diferente en msvc y gcc en la rutina vswprintf.
  6. No confíe en tipos de datos específicos del compilador, como __int32. Es muy probable que necesite algún tipo de tipo garantizado de 4 bytes de longitud (o algo así): use typedef combinado con compilación condicional ("#ifdef WIN32"). O utilice tipos proporcionados por la biblioteca multiplataforma. Por ejemplo, SDL proporciona tipos como Uint8, Qt 4 tiene quint32, etc. Esta es una práctica bastante común.
  7. Evite las llamadas directas al sistema operativo. Use funciones estándar para acceder a los archivos.
  8. Cuando tenga que usar llamadas específicas del sistema operativo, use la compilación condicional (#ifdef WIN32, etc.)
  9. Intente utilizar el mismo sistema de compilación en todas las plataformas. No hay MSBuild en Linux. Use gnumake, cmake, scons o qmake. Mientras que en algunos de esos sistemas tendrás que codificar en flags para compiladores diferentes, será posible usar el mismo script en todas partes. Por ejemplo, funciona muy bien con SConstructs. Y mantener un script de construcción para todas las plataformas puede ser más fácil que sincronizar los cambios en los diferentes sistemas de compilación.
  10. Para todas las operaciones que requieren interacción con el sistema operativo (Gui, manipulación de archivos), use bibliotecas multiplataforma. Qt es una buena elección.
+0

+1 para algunos puntos buenos. En realidad hay un MSBuild en Linux, pero probablemente nadie lo use para el código C++: http://www.mono-project.com/Microsoft.Build ... y cuando elijas funciones "estándar", ten en cuenta que es más de un estándar para elegir, y no todas las funciones estándar son portátiles, como aprendí recientemente: http://stackoverflow.com/questions/9896411/why-are-standard-library-function-names-different-between- windows-and-linux – Qwertie

+0

Re artículo 8 Agregaría, no esparce # ifdef a través de su código: tenga una 'plataforma.h' o similar, y ajuste el código dependiente de la plataforma en funciones independientes de la plataforma y concéntrelas. En otras palabras, amplíe su compilador y biblioteca con las características de portabilidad que falta que su código necesita, luego escriba el resto de su código de forma portátil. – Spike0xff

Cuestiones relacionadas