Frage

Ich habe an verschiedenen eingebetteten Systemen gearbeitet.Sie haben alle benutzt typedefs (oder #defines) für Typen wie UINT32.

Dies ist eine gute Technik, da sie dem Programmierer die Größe des Typs deutlich macht und Sie auf die Möglichkeit eines Überlaufs usw. aufmerksam macht.

Auf einigen Systemen wissen Sie jedoch, dass sich Compiler und Prozessor während der gesamten Lebensdauer des Projekts nicht ändern.

Was sollte also Ihre Entscheidung beeinflussen, projektspezifische Typen zu erstellen und durchzusetzen?

Bearbeiten Ich glaube, ich habe es geschafft, den Kern meiner Frage zu verlieren, und vielleicht sind es wirklich zwei.

Bei der eingebetteten Programmierung benötigen Sie möglicherweise Typen mit einer bestimmten Größe für Schnittstellen und auch zur Bewältigung eingeschränkter Ressourcen wie RAM.Dies lässt sich nicht vermeiden, aber Sie können die Basistypen des Compilers verwenden.

Für alles andere sind die Typen weniger wichtig.
Sie müssen darauf achten, keinen Überlauf zu verursachen, und möglicherweise auf die Register- und Stack-Nutzung achten.Was Sie vielleicht dazu führen könnte UINT16, UCHAR.Mit Typen wie UCHAR kann jedoch Compiler-Fluff hinzufügen.Da Register normalerweise größer sind, fügen einige Compiler möglicherweise Code hinzu, um das Ergebnis in den Typ zu zwingen.

i++;
kann werden
ADD REG,1
AND REG, 0xFF
was unnötig ist.

Ich denke, meine Frage hätte lauten sollen:

Was ist angesichts der Einschränkungen eingebetteter Software die beste Richtlinie für ein Projekt, an dem viele Leute arbeiten – von denen nicht alle über den gleichen Erfahrungsstand verfügen?

War es hilfreich?

Lösung

Ich verwende Typabstraktion sehr selten.Hier sind meine Argumente, sortiert nach aufsteigender Subjektivität:

  1. Lokale Variablen unterscheiden sich von Strukturmitgliedern und Arrays in dem Sinne, dass sie in ein Register passen sollen.Auf einem 32b/64b-Ziel ein lokales int16_t kann den Code im Vergleich zu einem lokalen int langsamer machen, da der Compiler entsprechend der Semantik von Operationen zu /force/overflow hinzufügen muss int16_t.Während C99 eine definiert intfast_t typedef, AFAIK, ein einfaches int passt genauso gut in ein Register, und es ist sicher ein kürzerer Name.

  2. Organisationen, denen diese Typdefinitionen gefallen, haben fast immer mehrere davon (INT32, int32_t, INT32_T, Ad infinitum).Organisationen, die integrierte Typen verwenden, sind daher in gewisser Weise besser dran, wenn sie nur einen Namenssatz haben.Ich wünschte, die Leute würden die Typedefs von stdint.h oder windows.h oder irgendetwas Vorhandenem verwenden;Und wenn ein Ziel nicht über diese .h-Datei verfügt, wie schwierig ist es dann, eine hinzuzufügen?

  3. Die Typedefs können theoretisch die Portabilität unterstützen, aber ich persönlich habe dadurch nie etwas gewonnen.Gibt es ein nützliches System, das Sie von einem 32b-Ziel auf ein 16b-Ziel portieren können?Gibt es ein 16b-System, dessen Portierung auf ein 32b-Ziel nicht einfach ist?Wenn außerdem die meisten Variablen Ints sind, profitieren Sie tatsächlich von den 32 Bits auf dem neuen Ziel, wenn dies jedoch der Fall ist int16_t, das wirst du nicht.Und die Orte, die schwer zu portieren sind, erfordern in der Regel ohnehin eine manuelle Inspektion;Bevor Sie einen Port ausprobieren, wissen Sie nicht, wo er sich befindet.Wenn nun jemand denkt, dass es so einfach ist, Dinge zu portieren, wenn man überall Typedefs hat – wenn die Zeit für die Portierung gekommen ist, was bei wenigen Systemen der Fall ist, schreiben Sie ein Skript, das alle Namen in der Codebasis konvertiert.Dies sollte nach der Logik „keine manuelle Inspektion erforderlich“ funktionieren und den Aufwand auf den Zeitpunkt verschieben, an dem er tatsächlich einen Nutzen bringt.

  4. Wenn nun Portabilität ein theoretischer Vorteil der Typedefs sein könnte, Lesbarkeit geht sicher den Bach runter.Schauen Sie sich einfach stdint.h an: {int,uint}{max,fast,least}{8,16,32,64}_t.Viele Arten.Ein Programm hat viele Variablen;Ist es wirklich so einfach zu verstehen, was sein muss? int_fast16_t und welche sein müssen uint_least32_t?Wie oft wechseln wir stillschweigend zwischen ihnen hin und her, wodurch sie völlig sinnlos werden?(Ich mag besonders BOOL/Bool/eBool/boolean/bool/int-Konvertierungen.Jedes Programm, das von einer ordentlichen Organisation geschrieben wird, die Typedefs vorschreibt, ist damit übersät.

  5. Natürlich könnten wir in C++ das Typsystem strenger gestalten, indem wir Zahlen in Instanziierungen von Vorlagenklassen mit überladenen Operatoren usw. einschließen.Das bedeutet, dass Sie jetzt Fehlermeldungen der Form „Klasse Number<int,Least,32> hat keine Operator+-Überladung für Argument vom Typ Klasse Number<unsigned long long,Fast,64>, Kandidaten sind …“ erhalten Nennen Sie dies auch nicht „Lesbarkeit“.Ihre Chancen, diese Wrapper-Klassen korrekt zu implementieren, sind mikroskopisch gering, und die meiste Zeit werden Sie darauf warten, dass die unzähligen Vorlageninstanziierungen kompiliert werden.

Andere Tipps

Der C99-Standard verfügt über eine Reihe von Ganzzahltypen mit Standardgröße.Wenn Sie einen Compiler verwenden können, der C99 unterstützt (gcc tut dies), finden Sie diese in <stdint.h> und Sie können sie einfach in Ihren Projekten verwenden.

Außerdem kann es in eingebetteten Projekten besonders wichtig sein, Typen als eine Art „Sicherheitsnetz“ für Dinge wie Einheitenumrechnungen zu verwenden.Wenn Sie C++ verwenden können, gibt es meines Wissens nach einige „Einheiten“-Bibliotheken, mit denen Sie in physischen Einheiten arbeiten können, die vom C++-Typsystem (über Vorlagen) definiert und als Operationen für die zugrunde liegenden Skalartypen kompiliert werden.In diesen Bibliotheken können Sie beispielsweise keine hinzufügen distance_t zu einem mass_t weil die Einheiten nicht in einer Reihe stehen;Sie erhalten tatsächlich einen Compilerfehler.

Auch wenn Sie nicht in C++ oder einer anderen Sprache arbeiten können, die es Ihnen ermöglicht, Code auf diese Weise zu schreiben, können Sie zumindest das C-Typ-System verwenden, um solche Fehler mit bloßem Auge zu erkennen.(Das war eigentlich die ursprüngliche Absicht von Simonyis ungarischer Notation.) Nur weil der Compiler Sie nicht anschreit, weil Sie a hinzugefügt haben meter_t zu einem gram_t bedeutet nicht, dass Sie solche Typen nicht verwenden sollten.Codeüberprüfungen werden dann viel produktiver bei der Entdeckung von Unit-Fehlern sein.

Meiner Meinung nach sind Sie auf eine minimale/maximale/spezifische Größe angewiesen nicht Nehmen Sie einfach an, dass (sagen wir) ein unsigned int ist 32 Bytes - verwenden uint32_t stattdessen (vorausgesetzt, Ihr Compiler unterstützt C99).

Ich verwende stdint.h-Typen gerne zum Definieren von System-APIs, insbesondere weil sie explizit angeben, wie groß Elemente sind.In den alten Tagen von Palm OS wurden die System-APIs mithilfe einer Reihe von Wischiwaschi-Typen wie „Word“ und „SWord“ definiert, die vom sehr klassischen Mac OS übernommen wurden.Sie führten eine Bereinigung durch und sagten stattdessen „Int16“, wodurch die API für Neulinge leichter verständlich wurde, insbesondere angesichts der seltsamen 16-Bit-Zeigerprobleme auf diesem System.Als sie Palm OS Cobalt entwickelten, änderten sie diese Namen erneut, um sie an die Namen von stdint.h anzupassen, was sie noch klarer machte und die Menge der zu verwaltenden Typedefs reduzierte.

Ich glaube, dass MISRA-Standards die Verwendung von Typedefs vorschlagen (erfordern?).

Aus persönlicher Sicht lässt die Verwendung von Typedefs keine Verwirrung hinsichtlich der Größe (in Bits/Bytes) bestimmter Typen aufkommen.Ich habe gesehen, wie leitende Entwickler beide Entwicklungsmethoden ausprobiert haben, indem sie Standardtypen verwendet haben, z. B.int und die Verwendung benutzerdefinierter Typen, z.UINT32.

Wenn der Code nicht portierbar ist, gibt es wenig real Vorteile bei der Verwendung von Typedefs, Jedoch Wenn Sie wie ich mit beiden Arten von Software arbeiten (tragbare und feste Umgebung), kann es nützlich sein, einen Standard beizubehalten und die maßgeschneiderten Typen zu verwenden.Zumindest weiß der Programmierer dann, wie Sie sagen, genau, wie viel Speicher er verbraucht.Ein weiterer zu berücksichtigender Faktor ist: Wie „sicher“ sind Sie, dass der Code nicht in eine andere Umgebung portiert wird?Ich habe gesehen, dass prozessorspezifischer Code übersetzt werden musste, weil ein Hardware-Ingenieur plötzlich eine Platine wechseln musste. Das ist keine schöne Situation, aber aufgrund der benutzerdefinierten Typdefinitionen hätte es viel schlimmer kommen können!

Konsistenz, Komfort und Lesbarkeit.„UINT32“ ist viel besser lesbar und beschreibbar als „unsigned long long“, was für einige Systeme das Äquivalent ist.

Außerdem können der Compiler und der Prozessor für die Lebensdauer eines Projekts unverändert bleiben, der Code aus diesem Projekt kann jedoch in einem anderen Projekt neues Leben finden.In diesem Fall ist es sehr praktisch, konsistente Datentypen zu haben.

Wenn Ihre eingebetteten Systeme irgendwie ein sicherheitskritisches System (oder ähnlich), es ist stark geraten (falls nicht erforderlich), um Typedefs über einfache Typen zu verwenden.

Als TK. hat schon mal gesagt, MISRA-C hat dazu eine (beratende) Regel:

Regel 6.3 (Beratung): Anstelle der grundlegenden numerischen Typen sollten Typdefinitionen verwendet werden, die Größe und Vorzeichen angeben.

(aus MISRA-C 2004;es ist Regel Nr. 13 (adv) von MISRA-C 1998)


Gleiches gilt in diesem Bereich auch für C++;z.B. JSF C++-Codierungsstandards:

AV-Regel 209 Eine Universaltypes -Datei wird erstellt, um alle zu verwendenden Entwickler zu definieren.Zu den Typen gehören:[uint16, int16, uint32_t usw.]

Benutzen <stdint.h> Macht Ihren Code für Unit-Tests auf einem PC portabler.

Es kann ziemlich hart für Sie sein, wenn Sie für alles Tests haben, es aber trotzdem auf Ihrem Zielsystem kaputt geht, weil ein int ist plötzlich nur noch 16 Bit lang.

Vielleicht bin ich komisch, aber ich verwende ub, ui, ul, sb, si und sl für meine Ganzzahltypen.Vielleicht wirkt das „i“ für 16 Bit etwas veraltet, aber mir gefällt das Aussehen von ui/si besser als von uw/sw.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top