Portabler Code ?!?


  • Mod

    Du darfst alles machen, was der C-Standard erlaubt. Das muss dann ein standardkonformer Compiler übersetzen können und es muss immer ein Programm rauskommen, was das gleiche tut. Die meisten Compiler sind heutzutage ziemlich standardkonform. Achtung: Der Microsoft C-Compiler unterstützt nur den C89-Standard! Das heißt, dass unter anderem inttypes.h nicht unbedingt vorhanden ist (mag sein, dass der MS-Compiler die C99-Header als Erweiterung doch kann(?), aber er kann auf jeden Fall nicht die neuen Grammatikfeatures).

    Wenn du dich an den Standard hältst, dann bist du auf jeden Fall auf der sicheren Seite. Der Standard kennt auch printf und braucht kein fprintf(stdout).

    Klugscheißer-Achtung: Der Standard kennt auch Umgebungen ohne Standardbibliothek. Ein Toaster mit C-Compiler wird eventuell kein Programm ausführen können, das printf braucht, weil er gar keine Ausgaben machen kann.

    Dann gibt es natürlich noch die Frage, wie man Sachen portabel programmieren kann, die nicht vom Sprachstandard abgedeckt werden. Z.B. Grafische Oberflächen, komplexe Dateisystemoperationen, Assembermikrooptimierungen, ...
    Da das nochmal ein eigenes Kapitel wäre, frage ich lieber erst einmal nach: Ist die Frage nun schon beantwortet?



  • zu stdout, stderr kannst du hier etwas erfahren
    http://wwwcip.informatik.uni-erlangen.de/old/tree/CIP/Manuals/unix/shell/kanaele.html

    inttypes.h wird z.b. der compiler von microsoft nicht fressen, weil der kein c99 kann.



  • ich dachte, dass es nicht genau festgelegt ist, wie groß jeder dateityp ist, z.b. dass int 4 bytes groß ist.

    wenn ich aber einen int mit 4 bytes brauche, dann sollte ich doch "uint32_t" verwenden, oder?



  • Wenn du unbedingt einen 4 Byte int brauchst, kannst du schon nicht mehr maximal portabel sein. Du musst dann immer Kompromisse schließen. Oftmals ist es auch nur Einbildung, dass man "unbedingt" etwas genau so und nicht anders benötigt.
    Du könntest auch unsigned long int (C89) verwenden, bei CHAR_BIT==8 ist der bis auf ganz seltene Bitpadding-Konstrukte auch 32Bit groß, aber du merkst schon an der Einschränkung, eben nicht immer.



  • Wutz schrieb:

    Wenn du unbedingt einen 4 Byte int brauchst, kannst du schon nicht mehr maximal portabel sein.

    In der Praxis geht es gar nicht darum, dass jede Code-Zeile unverändert für alle Plattformen gültig sein muss.
    Aber es ist super, wenn man bei einer Million Code-Zeilen in tausend Dateien weiß, dass man nur eine Handvoll Dateien bearbeiten muss, um das Programm an eine spezifische Umgebung anzupassen.

    Entscheidend ist dabei, dass man die Gemeinsamkeiten und Unterschiede der Zielplattformen kennt und Grundlagen als Voraussetzungen festlegt (z.B. ASCII oder Unicode) und konsequent modularisiert und kapselt.

    Das kann dann beispielsweise bedeuten, dass Verarbeitungsroutinen selbst keine Ausgabefunktionen aus den Bibliotheken nutzen, sondern nur eigene zentralisierte Funktionen.

    Man sollte, wenn Laufzeit eine große Rolle spielt, auch unterscheiden, wo man auf bestimmte Bitbreiten achten muss (um Schnittstellen, Größenrestriktionen oder Speichereffizienz einzuhalten,) und wo man es besser dem System überlässt, wie das auf Bit und Registerebene umgesetzt wird.

    Ciao, Allesquatsch



  • Wutz schrieb:

    Wenn du unbedingt einen 4 Byte int brauchst, kannst du schon nicht mehr maximal portabel sein. Du musst dann immer Kompromisse schließen. Oftmals ist es auch nur Einbildung, dass man "unbedingt" etwas genau so und nicht anders benötigt.
    Du könntest auch unsigned long int (C89) verwenden, bei CHAR_BIT==8 ist der bis auf ganz seltene Bitpadding-Konstrukte auch 32Bit groß, aber du merkst schon an der Einschränkung, eben nicht immer.

    ok, aber wie wird das dann gemacht, wenn es essentiell wichtig ist, dass ein dateityp eine bestimmte byte-anzahl hat? ich denke da an z.b. verschlüsselung, oder vielleicht auch noch treiberprogrammierung.

    sollte man am anfang eines programms prüfen, ob der dateityp die gewollte größe hat?
    z.b. so:

    .
    .
    .
    if(sizeof(char)!=1)
    {
          return 1;
    }
    if(sizeof(int)!=4)
    {
          return 1;
    }
    .
    .
    .
    

    oder wie wird das in der praxis gemacht?



  • Du baust deine eigene mytypes.h in der das gemacht wird.

    Da kannst du dann auch (wenn es sein muss) auf die jeweilige Plattform und Compiler reagieren.

    Nebenbei ist sizeof(char) per Definition 1.
    Es gibt/gab aber Rechner mit CHAR_BIT = 9 und dann hat da ein int 36 Bit.
    Und da ist dann sizeof(int) auch 4.



  • DirkB schrieb:

    Du baust deine eigene mytypes.h in der das gemacht wird.

    in der was gemacht wird? die prüfung?



  • ????? schrieb:

    DirkB schrieb:

    Du baust deine eigene mytypes.h in der das gemacht wird.

    in der was gemacht wird? die prüfung?

    Nein, du hast dort ein typedef für int32_t für einen int mit 32 bit. Ein unit16_t für einen unsigned mit 16 bit, etc.

    Diese Datei ist dann Plattformabhängig. Du weisst ja, dass auf dieser Plattform ein int immer 4 Byte hat und auf jener immer 2.

    Siehe zB stdint.h



  • Shade Of Mine schrieb:

    Nein, du hast dort ein typedef für int32_t für einen int mit 32 bit. Ein unit16_t für einen unsigned mit 16 bit, etc.

    Diese Datei ist dann Plattformabhängig. Du weisst ja, dass auf dieser Plattform ein int immer 4 Byte hat und auf jener immer 2.

    Siehe zB stdint.h

    ok, aber was soll ich machen, wenn die plattform einen bestimmten typ überhauptnicht unterstützt?

    soweit ich das jetzt verstanden habe, soll ich sowas machen:

    typedef int my_int32_t // wenn ich einen int brauche, der 4 byte groß ist, und ich weiß, dass auf diesem system int = 4 byte ist
    

    aber was soll ich machen, wenn ich einen 4 byte int brauche, das system aber überhaupt keinen "vorgefertigten" 4 byte typ bereitstellt?

    sagen wir mal, ich bräuchte einen typen, der genau 3 byte (= 24 bit) bereitstellt. auf meinem system gibt es KEINEN typen, der 3 byte hat.

    typedef <???> my_int24_t
    

    was müsste in diesem fall bei <???> stehen?



  • typedef char my_int24_t[3];
    // oder
    typedef struct
    {
    	char t24[3];
    }MyInt24_t;
    
    my_int24_t t1;
    // oder
    MyInt24_t t2;
    
    t1[0] = 0, t1[1] = 1 ...
    t2.t24[0] = 0 ...
    


  • CJosef schrieb:

    typedef char my_int24_t[3];
    // oder
    typedef struct
    {
    	char t24[3];
    }MyInt24_t;
    
    my_int24_t t1;
    // oder
    MyInt24_t t2;
    
    t1[0] = 0, t1[1] = 1 ...
    t2.t24[0] = 0 ...
    

    das wäre natürlich eine möglichkeit. aber ich kann dann variablen nicht so einfach deklarieren (??? - ist das das richtige wort?).
    einen int initialisiere und deklariere ich ja so:

    int variablen_name=1234;
    

    bei deinem beispiel geht das aber nicht so:

    my_int24_t t1=123;
    

    sondern mit array ?!? ich find das ein bissl mühsam.

    gäbe es noch eine andere möglichkeit?



  • Stimmt, ein Wert lässt sich nicht so einfach wie bei einem int zuweisen, das ginge umständlicher z.B. über Bitshift.
    Das gilt auch für Rechenoperationen (+/-*), Parameterübergabe an Standardfunktionen, etc.
    Dafür müsstest du dir eigene Funktionen bauen, ob sich der Aufwand lohnt ... ?



  • ...mhh... schrieb:

    ok, aber was soll ich machen, wenn die plattform einen bestimmten typ überhauptnicht unterstützt?

    Dann wirst du langsam aber sicher merken, dass die portability-Junkies eigentlich Schwachköpfe sind. Weil alles seine Grenzen hat. Wer Code portabel für eine x64-CPU und einen 24Bit-DSP und einen 8Bit-µC schreiben will, der sollte vielleicht doch lieber auf Marketing+Design umschulen.



  • DirkB schrieb:

    Es gibt/gab aber Rechner mit CHAR_BIT = 9

    es ist etwas offtopic, aber ich finde, es passt trotzdem ein wenig. welche rechner benutzen bzw. benutzten solch eine architektur ? könnt ihr mir da beispiele, links, o.ä. liefern ?



  • Hier einige Rechner mit 7 und 9bit char:
    http://en.wikipedia.org/wiki/36-bit_word_length



  • f.-th. schrieb:

    Hier einige Rechner mit 7 und 9bit char:
    http://en.wikipedia.org/wiki/36-bit_word_length

    perfekt 👍 🙂



  • In C ist CHAR_BIT aber mindestens 8. (Siehe die Links in http://www.c-plusplus.net/forum/300567)



  • In Bezug auf den portablen Code ob da ein char 8 bit gross ist oder eine andere Grösse hat, sollte man das ein wenig pragmatisch angehen.

    Es reicht das man weiss, das es solche "Exoten" gibt. Im Quelltext würde ich mir da nur einen Kopf machen, wenn das Programm real auf so einer Kiste laufen muss.



  • ...mhh... schrieb:

    aber was soll ich machen, wenn ich einen 4 byte int brauche, das system aber überhaupt keinen "vorgefertigten" 4 byte typ bereitstellt?

    Indem du liest, was hier vorgeschlagen wurde und es umsetzt.
    Wenn es keinen "vorgefertigten" Typ gibt, dann definierst du dir eben deinen eigenen.

    typedef unsigned long Typ32Bit;
    
    ...
    
    int main()
    {
      Typ32Bit x;
      assert( CHAR_BIT*sizeof(long)==32 );
      /* ab hier ist sichergestellt, dass dein neuer Typ genau 32 Bit enthält */
      ...
    }
    

    Bei dieser Implementierung kannst du alle Funktion/Operatoren, die für unsigned long definiert sind, benutzen, z.B. strtoul,printf("%lu",scanf("%lu",...
    Das befreit dich aber nicht von Maßnahmen zu Sicherstellung der Bytereihenfolge innerhalb deiner 4 Bytes, falls dein Programm solche Daten mit externen Quellen (Dateien,Netzwerk,...) tauscht.


Anmelden zum Antworten