2010-02-20 8 views
12

Per un progetto universitario ho bisogno di estendere un'applicazione C esistente, che alla fine funzionerà su un'ampia varietà di sistemi unix commerciali e non commerciali (FreeBSD, Solaris, AIX, ecc.).Scrivere un programma C portatile - quali cose considerare?

Quali cose devo considerare quando voglio scrivere un programma C che è più portabile?

+6

Considera http://stackoverflow.com/questions/1257923/why-is-it-difficult-to-write-portable-c-programs-closed e http://stackoverflow.com/questions/61499/making- codice portatile e, in effetti, gran parte di http://stackoverflow.com/search?q=[c]+portable. – dmckee

risposta

21

Il miglior consiglio che posso dare è quello di passare a una piattaforma diversa ogni giorno, testando come si va.
Questo farà sì che le differenze della piattaforma rimangano come un pollice dolente, e ti insegnano i problemi di portabilità allo stesso tempo.

Il salvataggio del test multipiattaforma per la fine porterà a un errore.

A parte

  • dimensioni intere possono variare.
  • I numeri in virgola mobile potrebbero essere rappresentati in modo diverso.
  • gli interi possono avere un diverso endianismo.
  • Le opzioni di compilazione possono variare.
  • include nomi di file possono variare.
  • le implementazioni dei campi bit possono variare.

è generalmente una buona idea quella di impostare il livello di avviso del compilatore il più in alto possibile, vedere il genere di cose il compilatore può lamentarsi.

+3

+1 per alti livelli di avviso del compilatore. –

+0

Mentre questo è molto saggio consigliare (+1), parlando a un principiante, diresti che questo si applica principalmente a C più avanzato, e non tanto a, ciò che la maggior parte delle persone riconoscerebbe come codice "semplice" - ad es. codice a cui non interessa se gli interi sono 2 byte o 200 byte? Voglio dire, "Hello World" è "Hello World", giusto? –

+0

No. Lo rivendico su tutta la linea. Al lavoro portiamo il codice su una nuova versione di g ++. Il codice che si stava compilando prima non riusciva a compilare, a causa di un file di inclusione mancante. Mantieni i livelli di avviso alti e utilizza più compilatori e più piattaforme il più possibile. BTW stiamo mantenendo le app CRUD/Console nel nostro dominio. – EvilTeach

3

È una lista molto lunga. La cosa migliore da fare è leggere degli esempi. Il source of perl, per esempio. Se osservi la fonte di perl, vedrai un gigantesco processo di costruzione di un file di intestazione che tratta circa 50 problemi di piattaforma.

Leggilo e piangi o prendi in prestito.

+3

Quando leggo Perl, piango. – Seth

+2

Questo è un problema completamente diverso. Questa è la fonte di Perl. Dovrebbe farti ululare. – bmargulies

1

L'elenco potrebbe essere lungo, ma non è così lungo quanto supporta anche Windows e MSDOS. Che è comune con molte utilità.

La tecnica usuale consiste nel separare i moduli dell'algoritmo di base da quelli che trattano il sistema operativo, fondamentalmente una strategia di astrazione stratificata.

Differenziare tra diversi sapori di Unix è piuttosto semplice in confronto. Sia attenersi a caratteristiche che utilizzano tutti gli stessi nomi RTL per, o guardare la convenzione di maggioranza per le piattaforme supportate e #ifdef nelle eccezioni.

4
  1. Utilizzare almeno due compilatori.
  2. Avere un sistema di generazione continua in posizione, che preferibilmente si basa sulle varie piattaforme di destinazione.
  3. Se non è necessario lavorare su un livello molto basso, provare a utilizzare una libreria che fornisce l'astrazione. È improbabile che non troverai librerie di terze parti che forniscono una buona astrazione per le cose che ti servono. Ad esempio, per rete e comunicazione, c'è ACE. Boost (ad es. File system) viene anche portato su diverse piattaforme. Queste sono librerie C++, ma potrebbero esserci anche altre librerie C (come ad esempio curl).
  4. Se devi lavorare a basso livello, tieni presente che le piattaforme occasionalmente hanno un comportamento diverso anche su cose come POSIX, dove dovrebbero avere lo stesso comportamento.Puoi dare un'occhiata al codice sorgente delle librerie qui sopra.
+0

+1 per l'idea di utilizzare più di un compilatore. Esistono strumenti in grado di automatizzarlo in qualche modo? Immagino che tecnicamente, usare un Makefile e scambiare il valore di $ (CC) e $ (FLAGS) potrebbe farlo, ma sarebbe bello se ci fosse un daemon o qualcosa che potesse verificare ciò in background ... – Miguel

+0

Usa cmake o qualche altro "strumento di creazione portatile" (vedi ad esempio http://stackoverflow.com/questions/3349956/portable-c-build-system). Per un esempio, vedi i miei file cmake di progetto (questi sono file .txt su http://crackpot.svn.sourceforge.net/viewvc/crackpot/trunk/crackpot/ e la sua directory di base). –

2

Un problema particolare di cui potrebbe essere necessario rimanere aggiornati (ad esempio, se i file di dati devono funzionare su più piattaforme) è endianness.

I numeri sono rappresentati in modo diverso a livello binario su diverse architetture. I sistemi big-endian ordinano il byte più significativo prima e i sistemi little-endian ordinano prima il byte meno significativo.

Se si scrivono alcuni dati grezzi in un file in un endianness e poi si legge di nuovo il file su un sistema con un endianness diverso, si avranno ovviamente dei problemi.

Si dovrebbe essere in grado di ottenere l'endianness in fase di compilazione sulla maggior parte dei sistemi da sys/param.h. Se è necessario rilevarlo in fase di runtime, un metodo consiste nell'utilizzare un'unione di int e char, quindi impostare char su 1 e vedere quale valore ha lo int.

1

Fare sempre riferimento agli standard POSIX per tutte le funzioni della libreria utilizzate. Parti dello standard sono ambigue e alcuni sistemi restituiscono diversi stili di codici di errore. Questo ti aiuterà a trovare in modo proattivo quelli veramente difficili da trovare bug di implementazione leggermente diversi.

6

Ho usato per scrivere utilità C che avrei poi supportato su architetture da 16 bit a 64 bit, incluse alcune macchine a 60 bit. Includevano almeno tre varietà di "endianness", diversi formati in virgola mobile, diverse codifiche di caratteri e diversi sistemi operativi (anche se Unix predominava).

  1. Rimani il più vicino possibile al C standard. Per le funzioni/le librerie che non fanno parte dello standard, come ampiamente si può trovare una base di codice ampiamente supportata. Ad esempio, per il collegamento in rete, utilizzare l'interfaccia socket BSD, con utilizzo minimo o minimo di opzioni socket di basso livello, segnalazione out-of-band, ecc. Per supportare un ampio numero di piattaforme disparate con personale minimo, è necessario rimanere con semplici funzioni di vaniglia.
  2. Essere molto consapevoli di ciò che è garantito dallo standard, vice qual è il tipico comportamento di implementazione. Ad esempio, i puntatori non hanno necessariamente le stesse dimensioni degli interi e i puntatori a tipi di dati diversi possono avere lunghezze diverse. Se devi fare supposizioni basate sull'implementazione, documentali con cura. Lint, o --strict, o qualsiasi altro set di strumenti di sviluppo abbia un equivalente, è di vitale importanza qui.
  3. I file di intestazione sono tuoi amici. Utilizzare macro e costanti definite da implementaton. Utilizza le definizioni dell'intestazione e #ifdef per isolare quelle istanze in cui è necessario coprire un numero limitato di alternative.
  4. Non dare per scontato che la piattaforma corrente utilizzi caratteri EBCDIC e interi decimali compressi. Ci sono un discreto numero di ASCII - anche due macchine a complemento. :-)

Con tutto ciò, se si evita la tentazione di scrivere cose più volte e #ifdef porzioni principali di codice, si scoprirà che la codifica e il test su piattaforme diverse aiuta a trovare i bug prima possibile. Finirai per produrre programmi più disciplinati, comprensibili e mantenibili.

+2

+1 per il punto 4. –

+0

E io credo che la libreria standard C sia la stessa su ogni sistema * nix. Tanto per lo 'standard' ... – helpermethod

+0

La libreria C Standard è la stessa. Molti programmi usano cose al di fuori dello standard C, come la comunicazione tra processi. Oltre a ciò, "la maggior parte portatile" probabilmente si estende oltre il sistema Unix. – mpez0

Problemi correlati