2010-02-20 15 views
12

Pour un projet à l'université, j'ai besoin d'étendre une application C existante, qui finira par tourner sur une grande variété de systèmes Unix commerciaux et non commerciaux (FreeBSD, Solaris, AIX, etc.).Écrire un programme C portable - quelles sont les choses à considérer?

Quelles sont les choses que je dois considérer lorsque je veux écrire un programme C qui est le plus portable?

+6

Considérez http://stackoverflow.com/questions/1257923/why-is-it-difficult-a-write-portable-c-programs-closed et http://stackoverflow.com/questions/61499/making- portable-code et en effet, beaucoup de http://stackoverflow.com/search?q=[c]+portable. – dmckee

Répondre

21

Le meilleur conseil que je puisse donner, c'est de passer à une plate-forme différente chaque jour, en testant au fur et à mesure.
Cela fera en sorte que les différences de plate-forme se tasser comme un pouce douloureux, et vous enseigner les problèmes de portabilité en même temps. L'enregistrement du test multiplate-forme pour la fin entraînera une panne.

Ce côté

  • tailles entières peuvent varier.
  • Les nombres à virgule flottante peuvent être représentés différemment.
  • Les entiers peuvent avoir un endianisme différent.
  • Les options de compilation peuvent varier.
  • Les noms de fichiers peuvent varier.
  • Les implémentations de champ de bit peuvent varier.

Il est généralement une bonne idée de définir votre niveau d'avertissement du compilateur aussi haut que possible, voir le genre de choses peut se plaindre au sujet du compilateur.

+3

+1 pour les niveaux d'avertissement élevés du compilateur. –

+0

Bien que ce soit très sage conseiller (+1), en parlant à un débutant, diriez-vous que cela s'applique principalement à C plus avancé, et pas tellement à, ce que la plupart des gens reconnaîtraient comme, "simple" code - par exemple, code qui ne se soucie pas si les entiers sont 2 octets ou 200 octets? Je veux dire, 'Hello World' est' Hello World', n'est-ce pas? –

+0

Non, je le revendique à tous les niveaux. Au travail, nous portons du code vers une nouvelle version de g ++. Le code qui compilait avant la compilation a échoué en raison d'un fichier d'inclusion manquant. Maintenez les niveaux d'alerte élevés et utilisez autant de compilateurs multiples et de plates-formes multiples que possible. BTW nous sommes en train d'installer des applications CRUD/Console dans notre domaine. – EvilTeach

3

C'est une très longue liste. La meilleure chose à faire est de lire des exemples. Le source of perl, par exemple. Si vous regardez la source de Perl, vous verrez un processus gigantesque de construction d'un fichier d'en-tête qui traite d'environ 50 problèmes de plate-forme.

Lisez-le et pleurez, ou empruntez.

+3

Quand je lis Perl, je pleure. – Seth

+2

C'est un problème entièrement différent. C'est la source de perl. Ca devrait te faire hurler. – bmargulies

1

La liste peut être longue, mais ce n'est pas aussi long que de supporter Windows et MSDOS. Ce qui est commun avec de nombreux services publics.

La technique habituelle consiste à séparer les modules de l'algorithme de base de ceux qui traitent du système d'exploitation - essentiellement une stratégie d'abstraction en couches.

La différenciation entre plusieurs saveurs d'unix est plutôt simple en comparaison. Soit s'en tenir à toutes les fonctionnalités utilisent les mêmes noms RTL pour, ou regarder la convention majoritaire pour les plates-formes prises en charge et #ifdef dans les exceptions.

4
  1. Utilisez au moins deux compilateurs.
  2. Avoir un système de construction continue en place, qui s'appuie de préférence sur les différentes plates-formes cibles.
  3. Si vous n'avez pas besoin de travailler très bas niveau, essayez d'utiliser une bibliothèque qui fournit l'abstraction. Il est peu probable que vous ne trouviez pas de bibliothèques tierces offrant une bonne abstraction pour les choses dont vous avez besoin. Par exemple, pour le réseau et la communication, il y a ACE. Boost (par exemple, système de fichiers) est également porté sur plusieurs plates-formes. Ce sont des bibliothèques C++, mais il peut y avoir aussi d'autres bibliothèques C (comme curl).
  4. Si vous devez travailler au niveau bas, sachez que les plates-formes ont parfois un comportement différent même sur des choses comme Posix où elles sont censées avoir le même comportement.Vous pouvez jeter un oeil sur le code source des bibliothèques ci-dessus.
+0

+1 pour l'idée d'utiliser plus d'un compilateur. Y a-t-il des outils qui peuvent automatiser cela quelque peu? Je suppose que techniquement, utiliser un Makefile et échanger la valeur de $ (CC) et $ (FLAGS) pourrait le faire, mais ce serait cool s'il y avait un démon ou quelque chose qui pourrait vérifier cela en arrière-plan ... – Miguel

+0

Utilisation cmake ou un autre "outil de construction portable" (voir par exemple http://stackoverflow.com/questions/3349956/portable-c-build-system). Pour un exemple, voir mes fichiers de projet cmake (ce sont des fichiers .txt à http://crackpot.svn.sourceforge.net/viewvc/crackpot/trunk/crackpot/ et son répertoire de base). –

2

Un problème particulier que vous devrez peut-être surveiller (par exemple, si vos fichiers de données doivent fonctionner sur plusieurs plates-formes) est endianness.

Les nombres sont représentés différemment au niveau binaire sur différentes architectures. Les systèmes big-endian ordonnent d'abord l'octet le plus significatif et les systèmes little-endian classent d'abord l'octet le moins significatif.

Si vous écrivez des données brutes dans un fichier dans un fichier et que vous les lisez ensuite sur un système avec une endianness différente, vous aurez évidemment des problèmes.

Vous devriez être en mesure d'obtenir l'endianness à la compilation sur la plupart des systèmes de sys/param.h. Si vous avez besoin de le détecter à l'exécution, une méthode consiste à utiliser une union d'un int et un char, puis définir le char sur 1 et voir quelle valeur a le .

1

Référez-vous continuellement aux normes POSIX pour toutes les fonctions de bibliothèque que vous utilisez. Certaines parties de la norme sont ambiguës et certains systèmes renvoient différents styles de codes d'erreur. Cela vous aidera à trouver de façon proactive ceux qui sont vraiment difficiles à trouver des bogues d'implémentation légèrement différents.

6

J'avais l'habitude d'écrire des utilitaires C que je prendrais alors en charge sur des architectures de 16 bits à 64 bits, y compris des machines de 60 bits. Ils comprenaient au moins trois variétés d '«endianness», différents formats de virgule flottante, différents codages de caractères et différents systèmes d'exploitation (bien qu'Unix ait prédominé). Restez aussi près que possible du C standard. Pour les fonctions/bibliothèques ne faisant pas partie de la norme, utilisez une base de code aussi largement que vous pouvez trouver. Par exemple, pour la mise en réseau, utilisez l'interface de socket BSD, avec une utilisation minimale ou minimale des options de socket de bas niveau, la signalisation hors bande, etc. Pour supporter un grand nombre de plates-formes disparates avec un minimum de personnel, vous devrez rester avec des fonctions plain vanilla.

  • Soyez très conscient de ce qui est garanti par la norme, quel est le comportement d'implémentation typique. Par exemple, les pointeurs n'ont pas nécessairement la même taille que les entiers, et les pointeurs vers différents types de données peuvent avoir des longueurs différentes. Si vous devez faire des hypothèses dépendantes de la mise en œuvre, documentez-les de manière exhaustive. La charpie, ou --strict, ou quel que soit l'équivalent de votre jeu d'outils de développement, est ici d'une importance vitale.
  • Les fichiers d'en-tête sont vos amis. Utilisez les macros et les constantes définies par implementaton. Utilisez les définitions d'en-tête et #ifdef pour isoler les instances où vous devez couvrir un petit nombre d'alternatives.
  • Ne supposez pas que la plate-forme actuelle utilise des caractères EBCDIC et des entiers décimaux compressés. Il y a aussi un bon nombre de machines ASCII à complément de deux. Avec tout cela, si vous évitez la tentation d'écrire des choses plusieurs fois et #ifdef des portions majeures de code, vous constaterez que le codage et les tests sur des plates-formes disparates aident à trouver des bogues plus tôt. Vous finirez par produire des programmes plus disciplinés, compréhensibles et maintenables.

  • +2

    +1 pour le point 4. –

    +0

    Et je pense que la librairie standard C est la même sur tous les systèmes * nix. Voilà pour la 'norme' ... – helpermethod

    +0

    La bibliothèque C Standard est la même. Beaucoup de programmes utilisent des choses en dehors de la norme C, telles que la communication inter-processus. En outre, "le plus portable" dépasse probablement le système Unix. – mpez0