Wie werden C99-Standardtypen für maximale Portabilität UND Effizienz auf den meisten Plattformen verwendet?

9

Erstens, hier ist, was ich verstehe und denke, was für die Frage wahr ist.

  1. Verwenden Sie schnelle Datentypen für einzelne Variablen wie Zähler oder for loop-Indizes. Zum Beispiel:

    %Vor%

    Ich denke, der geeignetste Typ hier ist uint_fast8_t , da index niemals 255 überschreiten kann und dies die schnellste Implementierung für alle Plattformen sein wird. Wenn ich stattdessen unsigned int verwende, ist es bei & gt; = 16-Bit-Plattformen am schnellsten, wird aber bei & lt; 16-Bit-Plattformen langsamer sein, da int standardmäßig mindestens 16 Bits aufweist. Wenn ich uint8_t verwende, ist es auch langsamer auf & gt; 8-Bit-Plattformen, da der Compiler eine AND 0xFF -Anweisung hinzufügt, um den Überlauf für jedes Inkrement zu überprüfen (mein ARM7-Compiler macht das sogar bei voller Geschwindigkeitsoptimierung). size_t ist auch keine Option, da sie größer als die native Integer-Größe sein kann.

    Schlechte Seite (?) wenn ein Überlauf für 8 Bits erwartet wird, wird es nicht passieren. Der Programmierer sollte manuell nach einem Überlauf suchen (wie er / sie sollte IMHO), was zu einem fehlerhaften Code führen kann, wenn er vergessen wird. Auch der Compiler (und sogar PC-Lint zu meiner Überraschung) wird keine Warnung / Problem ausgeben, wenn LOOP_COUNT "zufällig" auf einen Wert größer als 255 auf & gt; 8 Bit Plattformen gesetzt wird, aber die Warnung wird auf einer 8 Bit Plattform erzeugt , wodurch die Portabilität verringert und Fehler eingeführt werden, dies kann jedoch mit #if checks vermieden werden.

  2. Verwenden Sie möglichst wenig Datentypen, wenn die Speichernutzung wie in Arrays oder Strukturen von Bedeutung ist. Zum Beispiel:

    %Vor%

    Es ist der portabelste und effizienteste Weg, Arrays zu deklarieren, wenn die Speicherbelegung von Bedeutung ist. Dieser Typ gibt ein Bytearray an, wenn auf der Plattform ein Bytezugriff möglich ist, und gibt ansonsten das kleinste zugängliche width Ganzzahlarray an. Außerdem können die wenigsten Typen in Strukturen verwendet werden, wenn wir Arrays der Struktur haben.

    Der kleinste Typ kann auch die Probleme haben, die schnelle Typen haben, da die Breite der Variablen auf verschiedenen Plattformen für beide Fälle geändert werden kann.

  3. Vermeiden Sie Datentypen mit fester Breite so weit wie möglich, da sie auf einigen Plattformen nicht existieren können, mit Ausnahme des Hardware-Registerzugriffs, der Kommunikationsprotokollzuordnung usw., wo wir die genauen Bits der Variablen kennen müssen. Zum Beispiel:

    %Vor%

    Normalerweise sollte __attribute__((packed)) (oder etwas Ähnliches) verwendet werden, um sicherzustellen, dass für diese Fälle kein Padding eingefügt wird, da dies ein Problem für sich sein kann.

Nun, wenn mein Verständnis stimmt, denke ich, dass die wenigsten Datentypen eher in Arrays oder Strukturen verwendet werden. Schnelle Datentypen werden eher für einzelne Variablen verwendet und feste Datentypen werden wahrscheinlich nicht in der richtigen Reihenfolge verwendet um maximale Portabilität und Effizienz zu erreichen. Aber "schnell" und "am wenigsten" jedes Mal zu tippen, ist nicht ermutigend. Also, ich denke an einen Typsatz wie folgt:

%Vor%
  • Zuerst und die wichtige Frage ist, ist mein Verständnis wahr?
  • Was wäre der portabelste und effizienteste Weg zur Verwendung von C99-Standardtypen und wie würden Sie sie deklarieren, wenn das nicht der Fall ist?
  • Ist mein Typsatz sinnvoll oder wird wahrscheinlich fehlerhafter Code erzeugt?

Außerdem würde ich mich freuen zu wissen, wie und wo Sie C99-Standardtypen verwenden.

    
obareey 03.04.2013, 17:32
quelle

1 Antwort

4

Sehr portablen Code zu schreiben ist schwer. Das Schreiben von sehr portablem Code, der optimal ist und richtig funktioniert, ist noch schwieriger.

Wenn es machbar ist, würde ich für den Großteil der Zeit vorschlagen, grundlegende Typen wie int , char usw. anstelle von uint8_t oder uint8_fast_t zu verwenden. Die Typen int und char sind garantiert vorhanden. Daran besteht kein Zweifel. Natürlich brauchen wir manchmal ein bestimmtes Verhalten aus dem Code, und das erfordert einen bestimmten Typ - aber dieser Code wird wahrscheinlich brechen, wenn das System diesen genauen Typ nicht unterstützt.

Für Ihr erstes Beispiel ist es äußerst unwahrscheinlich, dass Sie eine bessere Leistung erhalten als mit int , es sei denn, Ihr Code ist so ausgelegt, dass er (auch) auf 8-Bit-Prozessoren läuft. Bei einem 16-, 32- oder 64-Bit-Prozessor ist die native Größe die schnellste für Schleifen (wobei unsigned auf 64-Bit-Maschinen etwas besser ist, da keine Zeichenerweiterung erforderlich ist).

In Ihrem zweiten Beispiel spielt es nur eine Rolle, ob das Array groß genug ist, um Platz zu sparen, anstatt entweder char oder int oder short oder was auch immer für den Inhalt sinnvoll ist. Auf modernen Maschinen (einschließlich vieler eingebetteter Plattformen und selbst wenn der Stapel verwendet wird) sind 400 Bytes nicht wirklich so viel.

Für Ihr drittes Beispiel müssen Sie natürlich für Protokolle Typen verwenden, die genau der Protokolldefinition entsprechen, oder es werden Dinge falsch laufen. Auf Plattformen, die nicht den richtigen Typ unterstützen, muss dies auf eine bestimmte Art und Weise gelöst werden - wie Sie vorgehen, hängt davon ab, was die Plattform tatsächlich unterstützt.

Also, um Ihre konkreten Fragen zu beantworten:

  • Scheint so, als ob Sie das Gesamtkonzept verstehen. Aber du scheinst es auch zu sein versuche es weiter zu schieben, als es nötig ist, wenn das passiert ist macht Sinn.
  • Nicht zutreffend.
  • Übermäßige Verwendung von "speziellen Typ" -Variablen ist wahrscheinlich:

    1. Verlangsamen Sie die Dinge,
    2. kann möglicherweise Fehler verursachen, insbesondere wenn sie nicht konsistent verwendet werden.

Denken Sie auch daran, dass Leistung oft ein Fall von 90% der Zeit ist, die von 10% des Codes genommen wird. Es ist entscheidend, wo (unter normaler Verwendung) der Code seine Zeit verbringt. Natürlich kann es bei der Portierung von Code auf verschiedene Systeme und Architekturen vorkommen, dass sich der Leistungsengpass aufgrund der Beziehung zwischen der Prozessorgeschwindigkeit, der Größe der Caches und der Speichergeschwindigkeit verschiebt. Ein System mit hoher Prozessorgeschwindigkeit, aber (tatsächlich) kleine Caches können manchmal schlechter abschneiden als ein ähnliches System mit niedrigerer Taktrate und größeren Caches, als ein Beispiel.

    
Mats Petersson 03.04.2013 18:34
quelle