Travail sur un projet intégré, j'ai essayé de travailler dans tous les C une fois, et ne pouvaient tout simplement pas le supporter. Il était tellement détaillé qu'il a du mal à lire quoi que ce soit. Aussi, j'ai aimé la optimisé-pour-embedded conteneurs j'avais écrit, qui avait à son tour en beaucoup moins fort et plus difficile à corriger #define
blocs.
Code en C++ ressemblait à:
if(uart[0]->Send(pktQueue.Top(), sizeof(Packet)))
pktQueue.Dequeue(1);
se transforme en:
if(UART_uchar_SendBlock(uart[0], Queue_Packet_Top(pktQueue), sizeof(Packet)))
Queue_Packet_Dequeue(pktQueue, 1);
qui beaucoup de gens vont probablement dire que c'est bien, mais devient ridicule si vous devez faire plus d'un couple de "méthode" à des appels à la ligne. Deux lignes de C++ serait à son tour tenu cinq de C (en raison de 80-char limites de longueur de ligne). Les deux devraient générer le même code, c'est pas comme si le processeur cible soigné!
Une seule fois (en 1995), j'ai essayé d'écrire beaucoup de C pour un multiprocesseur de traitement de données de programme. Le genre où chaque processeur possède sa propre mémoire et le programme. Les fournisseur compilateur est un compilateur C (une sorte de HighC dérivés), de leurs bibliothèques ont été à code source fermé, donc je ne pouvais pas utiliser GCC pour construire, et à leurs Api ont été conçus avec l'état d'esprit que vos programmes s'agit principalement de la initialiser/processus/mettre fin à la variété, de sorte inter-processeur de communication a été, au mieux, rudimentaire.
J'ai eu environ un mois avant que j'ai donné, a trouvé une copie du cfront, et piraté dans le makefile si je pouvais utiliser C++. Cfront n'a même pas le soutien de modèles, mais le code C++ est beaucoup, beaucoup plus claire.
Générique, type-safe structures de données (à l'aide de modèles).
La chose la plus proche C est à des modèles est de déclarer un fichier d'en-tête avec beaucoup de code qui ressemble à ceci:
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{ /* ... */ }
ensuite, tirez-le avec quelque chose comme:
#define TYPE Packet
#include "Queue.h"
#undef TYPE
Notez que cela ne fonctionne pas pour les types composés (par exemple, pas de files d'attente d' unsigned char
) à moins de faire un typedef
première.
Oh, et n'oubliez pas, si ce code n'est pas utilisé n'importe où, alors vous ne savez même pas si elle est syntaxiquement correcte.
EDIT: encore Une chose: vous devez manuellement gérer l'instanciation de code. Si votre "template" le code n'est pas toutes les fonctions en ligne, alors vous aurez à mettre dans un certain contrôle pour s'assurer que les choses se instancié qu'une seule fois donc votre éditeur de liens n'est pas de cracher un tas de "plusieurs instances de Foo" erreurs.
Pour ce faire, vous aurez à mettre la non-incorporé des trucs dans la "mise en œuvre" de section dans le fichier d'en-tête:
#ifdef implementation_##TYPE
/* Non-inlines, "static members", global definitions, etc. go here. */
#endif
Et puis, dans un lieu dans tout votre code par modèle variante, vous devez:
#define TYPE Packet
#define implementation_Packet
#include "Queue.h"
#undef TYPE
Aussi, cette mise en œuvre de l'article doit être en dehors de la norme #ifndef
/#define
/#endif
litanie, parce que vous pouvez inclure le modèle d'en-tête de fichier dans un autre fichier d'en-tête, mais faut instancier par la suite, dans un .c
le fichier.
Yep, ça devient laid rapide. C'est pourquoi la plupart des programmeurs C, n'essayez même pas.
RAII.
En particulier dans les fonctions avec plusieurs points de retour, par exemple, ne pas avoir à se souvenir de la libération du mutex sur chaque point de retour.
Eh bien, oubliez votre joli code et de s'habituer à l'ensemble de vos points de retour (à l'exception de la fin de la fonction) en cours de goto
s:
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{
TYPE * result;
Mutex_Lock(this->lock);
if(this->head == this->tail)
{
result = 0;
goto Queue_##TYPE##_Top_exit:;
}
/* Figure out `result` for real, then fall through to... */
Queue_##TYPE##_Top_exit:
Mutex_Lock(this->lock);
return result;
}
Les destructeurs en général.
I. e. vous écrivez un d'tor une fois pour MyClass, alors si une instance de Maclasse est un membre de MyOtherClass, MyOtherClass n'a pas explicitement deinitialize l'instance de Maclasse - son d'tor est appelé automatiquement.
Construction de l'objet doit être explicitement traitées de la même manière.
Les espaces de noms.
C'est en fait un simple correctif: simplement ajouter un préfixe sur chaque symbole. C'est la cause première de la source de ballonnements que j'ai parlé plus tôt (étant donné que les classes sont implicites des espaces de noms). La C les gens ont vécu cela, eh bien, jamais, et ne sera probablement pas voir ce qu'est l'affaire.
YMMV