Typumwandlung: int -> char[4]



  • typedef union { 
      int Integer; 
      char bytes[4]; 
    } IntToChar4;
    

    Das ist höchstwarscheinlich nicht Standardkonform - dass das klapt liegt höchst wahrscheinlich an deinem Compiler (mit MSVC Net 2003 kann man es so machen - aber ich vermutte das dass kein Standard ist)

    zum Problem:
    ich würde einfach Bitoperationen verwenden - die wären sicherlich schöner als das Rumtricksen mit Zeigern



  • Ein int besteht aus sizeof(int) * 8 Bits

    Ein char besteht aus sizeof(char) * 8 Bits

    Zunächst stellt sich die doch erst die Frage ob ein int vier chars passt (C99 definiert doch nicht das ein int in vier chars passt - oder?):
    Falls siezof(int) / sizeof(char) == 4 (true) gleich eins ist, dann ja

    (Dein Programm könnte ja auf einem Rechner ausgeführt werden, der andere Größen für Datentypen bereit stellt – obwohl das extrem unwahrscheinlich ist, bzw. du weißt auf welchen Rechnern das Programm später ausgeführt wird)

    Die einzelnen Bits von dem Integer nummeriere ich von Rechts nach Links beginnend mit der 0. Das niederwertigste Bit bezeichne ich mit dem Index 0 – das höchstwertige Bit mit dem Index n

    Ein Integer hat n Bits: BitSizeOfInt = sizeof(int) * 8
    Der vierte Teil davon ist: BitSizeOfChar = sizeof(char) * 8; oder SizeOfInt / 4;

    n, …, 9,8,7,6,4,3, 2, 1, 0

    Nun teile ich den Integer in vier gleich große Stücke auf

    Den erste Teil des Integer geht von n bis n-BitSizeOfChar+1
    Der zweite von n-SizeOfChar bis n-2SizeOfChar+1
    Der dritte geht von n-2*SizeOfChar bis n-3*SizeOfChar+1
    Der vierte geht von n-3
    SizeOfChar bis 0

    Nun legen wir ein char Array an: char Array[4]; // Array ist nicht der beste Name

    BTW: In C99 gibt es auch den // Komentar:
    “Except within a character constant, a string literal, or a comment, the characters //
    introduce a comment that includes all multibyte characters up to, but not including, the
    next new-line character“

    Den ersten Teil des Integer packe ich in die Variable Array[0]:

    Dazu ist eine Rechtsverschiebung von 3*BitSizeOfChar Bist notwendig
    (man braucht sich hier keine Gedanken machen ob man es mit einem unsinged oder einem signed char zu tun hat – an der internen Bit Repräsentation ändert sich nichts – nur der Wert von Array[0] wird anders interpretiert – definiert der C Standard überhaupt ob ein char signed oder unsigned ist? – in C++98 ist das nicht so – dort ist nicht definiert ob ein char signed oder unsigned ist)

    int zahl;
    Array[0] = zahl >> 3*BitSizeOfChar; // der >> hat ein geringere Priorität als der * Operator - zur bessern Lesbarkeit sollte man trotzdem Klammern
    Array[1] = zahl >> 2*BitSizeOfChar;
    Array[2] = zahl >> 1*BitSizeOfChar;
    Array[3] = zahl;
    

    Eine Frage die sich noch stellt – was passiert wenn man einem char einen Int Wert zuweißt?
    Angenommen ein int ist 32 Bit groß und ein char 8 Bit – dann werden die Bits 32 bis 9 vom Integer verworfen und nur die Bits von 8 bis 0 in den char übertragen

    Statt Rechtsverschieben und Linksverschieben kann man auch mit 2er Potenzen multiplizieren – vielleicht ist dass sogar schneller – auch wenn das früher genau anders herum war – müsste man mal testen ob Shiften um 4 Bits schneller oder langsammer ist als die Multiplikation mit 16

    Das ganze habe ich nicht getestet und vielleicht habe ich einen schwerwiegenden Fehler mit eingebaut – glaub jedoch das es so ungefähr funktioniert



  • Vertexwahn schrieb:

    Ein int besteht aus sizeof(int) * 8 Bits

    Ein char besteht aus sizeof(char) * 8 Bits

    Nörgler würden sagen, dass ein char nicht zwingend aus 8 Bits besteht. Das betrifft aber nur absolute Exoten.

    Vertexwahn schrieb:

    Zunächst stellt sich die doch erst die Frage ob ein int vier chars passt (C99 definiert doch nicht das ein int in vier chars passt - oder?):

    Richtig, der Standard sagt nichts darüber aus, wie groß ein int ist, lediglich dass es >= short ist.

    Vertexwahn schrieb:

    Falls siezof(int) / sizeof(char) == 4 (true) gleich eins ist, dann ja

    Das sizeof(char) kannst du dir sparen, denn es ist immer 1. Das ist vom Standard definiert.

    Vertexwahn schrieb:

    ...

    Unabhängig davon ob es funktioniert oder nicht. Aber wäre es mit memcpy() nicht schneller erledigt?



  • > The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type.

    > When applied to an operand that has type char, unsigned char, or signed char,
    (or a qualified version thereof) the result is 1.

    soll das jetzt heißen ein char ist immer ein Byte groß?

    mmh dann könnte sizeof(char) einen anderen wert haben wie:
    char array[10];
    sizeof(array[0]);

    oder?



  • TactX schrieb:

    Vertexwahn schrieb:

    Ein int besteht aus sizeof(int) * 8 Bits

    Ein char besteht aus sizeof(char) * 8 Bits

    Nörgler würden sagen, dass ein char nicht zwingend aus 8 Bits besteht. Das betrifft aber nur absolute Exoten.

    Naja, der Standard würde es eher so schreiben:
    Ein int besteht aus 'sizeof(int) * CHAR_BIT' Bits.
    Ein char besteht aus 'sizeof(char) * CHAR_BIT' bzw. 'CHAR_BIT' Bits.
    🙂

    Vertexwahn schrieb:

    müsste man mal testen ob Shiften um 4 Bits schneller oder langsammer ist als die Multiplikation mit 16

    Sehr unwahrscheinlich, dass Shiften langsamer ist, vielleicht auf irgendwelchen Exoten.

    Vertexwahn schrieb:

    Angenommen ein int ist 32 Bit groß und ein char 8 Bit – dann werden die Bits 32 bis 9 vom Integer verworfen und nur die Bits von 8 bis 0 in den char übertragen

    Nicht ganz. Da int hier nur 32 Bits hat, wird ein gängiger Prozessor Bit 0 bis 7 ins char kopieren und Bit 8 bis 31 verwerfen. Abhängig davon, ob char signed oder unsigned ist, werden noch entsprechende Anpassungen vorgenommen.

    @Vertexwahn
    Könntest du dir mal bitte angewöhnen, ordentlich zu quoten?



  • C99:

    Values stored in non-bit-field objects of any other object type consist of n * CHAR_BIT bits, where n is the size of an object of that type, in bytes.

    Ich dachte eine Byte hat immer 8 Bit

    Könntest du dir mal bitte angewöhnen, ordentlich zu quoten?

    ich versuchs 😉 - wie ersetze ich "Zitat" durch einen Namen?



  • groovemaster schrieb:

    Vertexwahn schrieb:

    müsste man mal testen ob Shiften um 4 Bits schneller oder langsammer ist als die Multiplikation mit 16

    Sehr unwahrscheinlich, dass Shiften langsamer ist, vielleicht auf irgendwelchen Exoten.

    Der P4 ist ein Exot? 😮

    Der P4 hat keinen Barrel Shifter. Viele Leute sagen, dass er auch deswegen so lahm ist...



  • Vertexwahn schrieb:

    ich versuchs 😉 - wie ersetze ich "Zitat" durch einen Namen?

    Indem du in das Editfeld hinter dem Quote Button einen Namen reinschreibst.

    TactX schrieb:

    Der P4 hat keinen Barrel Shifter. Viele Leute sagen, dass er auch deswegen so lahm ist...

    Whoa, das hört sich ja ziemlich übel an. Naja, dazu kann ich leider nix sagen, weil ich meinen letzten Pentium '00 zu Grabe getragen hab. Aber normalerweise sollte sich Shiften auf Hardwareebene schon schneller realisieren lassen wie Multiplikationen, oder zumindest nicht langsamer.



  • groovemaster schrieb:

    TactX schrieb:

    Der P4 hat keinen Barrel Shifter. Viele Leute sagen, dass er auch deswegen so lahm ist...

    Whoa, das hört sich ja ziemlich übel an. Naja, dazu kann ich leider nix sagen, weil ich meinen letzten Pentium '00 zu Grabe getragen hab. Aber normalerweise sollte sich Shiften auf Hardwareebene schon schneller realisieren lassen wie Multiplikationen, oder zumindest nicht langsamer.

    Google mal nach "p4 barrel shifter". Kommen einige Links dazu. Auf die Gefahr, dass das jetzt zu sehr OT wird, aber intel sollte die P4-Kacke endlich einstampfen...



  • groovemaster schrieb: schrieb:

    Whoa, das hört sich ja ziemlich übel an. Naja, dazu kann ich leider nix sagen, weil ich meinen letzten Pentium '00 zu Grabe getragen hab. Aber normalerweise sollte sich Shiften auf Hardwareebene schon schneller realisieren lassen wie Multiplikationen, oder zumindest nicht langsamer.

    Früher war es in Programmiererkreisen üblich, Ganzzahlmultiplikationen mit 2 bzw. Ganzzahldivisionen durch 2 mit Hilfe der entsprechenden Shift-Operationen durchzuführen, da dies einen kleinen Performancegewinn im Vergleich zur "echten" mathematischen Operation darstellte. Heutzutage ist dieser Performancegewinn nicht mehr vorhanden, da alle
    derzeitigen Architekturen auf solche Operationen optimiert sind. Aus Gründen der Leserlichkeit sollte man also heutzutage nicht mehr auf diese Art der trickreichen Programmierung zurückgreifen. Darüber hinaus optimiert der Compiler in den meisten Fällen solche Dinge automatisch.



  • Vertexwahn schrieb:

    Darüber hinaus optimiert der Compiler in den meisten Fällen solche Dinge automatisch.

    Das ist schon klar. Ist auch der Hauptgrund, warum man auf solche Shift Tricks heutzutage verzichten kann.
    Nur sind die CPU's heutzutage wirklich so effizient? Hab leider nur einen "alten" Athlon Barton, und weiss, dass dort Multiplikationen sehr schnell sind. Aber schneller oder zumindest genauso schnell wie Shifts? Hört sich zumindest ungewohnt an. Aber das ist jetzt zu sehr OT. 🙂



  • Vielleicht hilft dir folgende Funktion welche ich mal geschrieben habe:
    (ich verstehe jetzt nicht ganz den Unterschied zwischen char[4] und String, hab jetzt auch nicht das komplette Topic gelesen, aber vielleicht nutzt dir der Code ja trotzdem was)

    unsigned char *int_to_ascii(int punkte)
    {
    	static unsigned char temp[4]={'\0','\0','\0', '\0'};
      //punkte darf maximal 3stellen haben
    
      if(((punkte-punkte%100)/100)!=0 )
    	 temp[0]=((punkte-punkte%100)/100)+'0';	
    	else
    	 temp[0]=' ';
    
    	if((((punkte%100-punkte%10)/10)!=0) || (temp[0]!=' ') )
       temp[1]=((punkte%100-punkte%10)/10)+'0';
      else
       temp[1]=' ';
    
      if((punkte%10)!=0 || (temp[1]!=' ') )
    	 temp[2]=(punkte%10)+'0';
    	else
    	 temp[2]=' ';  
    
    	temp[3]='\0';
    
    	return temp;
    }
    

    Grüße,
    Harri



  • 😮 DailyWTF? 😃

    harry3 schrieb:

    hab jetzt auch nicht das komplette Topic gelesen

    Wäre aber vielleicht besser gewesen.



  • @harry3:

    Deine Funktion wandelt die letzten vier stellen einer int Zahl in einen "String" um - das war nicht gesucht und bringt den fragenden nicht weiter

    harry3 schrieb:

    temp[0]=((punkte-punkte%100)/100)+'0';

    das funktioniert zwar auf den meisten Rechnern ist, aber nicht besonders schön - ich will dir ja nicht viel zu programmierstill sagen - aber für größere Projekte (z. B. kleine Computerspiele) solltest du erst ein wenig etwas über allgemeine Prinzipien von Softwareentwicklung lernen - macht sich später vielleicht einmal bezahlt



  • Vertexwahn schrieb:

    Deine Funktion wandelt die letzten vier stellen einer int Zahl in einen "String" um - das war nicht gesucht und bringt den fragenden nicht weiter

    ausserdem gibts 'itoa' und 'sprintf'....



  • groovemaster schrieb:

    😮 DailyWTF? 😃

    harry3 schrieb:

    hab jetzt auch nicht das komplette Topic gelesen

    Wäre aber vielleicht besser gewesen.

    Aus dem ersten Beitrag ist nicht gerade gut herauslesbar gewesen, was wirklich gewünscht ist.
    Und man kann nicht verlangen, dass man 2 Seiten liest und erst dann postet.
    Deshalb hab ich auch dazugeschrieben dass ich mir nicht sicher bin. (also KEEP COOL, nicht gleich wegen jedem Blödsinn aufregen wenns denn gut gemein ist :p )

    @Vertexwahn: Was würdest du vorschlagen um den Code optisch aufzupeppen? 😃
    Allerdings sollte er gleichschnell bleiben und gleich klein(im Speicher), also keine Schleifen etc.(mit zusätzlichen Variablen) einbauen!!!(ist nämlich nicht für einen PC geschrieben->wenig Speicher, wenig Power).

    @net: Aufm PC schon, aber nicht für das Kastl(Texas Instruments 200), für den ich programmiere.
    sprintf() gäbs zwar schon, aber das braucht knapp 100byte an Speicher!!! Während meine Funktion wohl nur ein paar bytes braucht. Warm ich um jedes byte kämpfe? Siehe oben!

    Grüße,
    Harri



  • harry3 schrieb:

    @Vertexwahn: Was würdest du vorschlagen um den Code optisch aufzupeppen?

    Konsequentes Einrücken 😃
    ich konnte ja nicht wissen das du auf einer Umgebung arbeitest, die nicht den vollen sprachumfang unterstützt und das du versuchst auf geschwindigkeit zu optimieren und nicht auf sauberen, wartbaren code

    harry3 schrieb:

    Und man kann nicht verlangen, dass man 2 Seiten liest und erst dann postet

    doch - kann man - ansonsten könnte es ja passieren, dass man glatt am problem vorbeiredet



  • Sie unterstützt schon fast den gesamten Sprachumfang von Ansi C, aber das problem ist eben, das viele C-typische Befehle zwar nutzbar sind, aber eben langsam sind und vor allem viel Speicher brauchen.

    Wegen den Zeileneinrückungen: In der IDE passts, aber scheinbar übernimmt das Forum die Tabs nicht 1:1 von dem IDE Text-Editor.

    doch - kann man - ansonsten könnte es ja passieren, dass man glatt am problem vorbeiredet

    Ja, kann man, aber ich hab gestern noch einiges zu tun gehabt, und ich dachte ich stell mal schnell den Code online, vielleicht hilfts ja, und wenn nicht, naja, kann man ja auch drüber hinwegsehen. War ja gut gemeint.

    Nur keine Angst, ansonsten lese ich schon wenn möglich alles.

    Grüße,
    Harri



  • harry3 schrieb:

    @net:
    sprintf() gäbs zwar schon, aber das braucht knapp 100byte an Speicher!!!

    das ist aber ein sparsames printf 🙂
    biste sicher das das nicht irgendwo im rom steckt?



  • Hab gerade "nachgemessen": printf("") braucht doch ganze 206bytes.(ist aber für PC Verhältnisse immer noch winzig)
    Der Compiler optimiert sehr gut in Bezug auf Größe, mein Spiel "Memory" hat z.B. nur knapp 5kbytes. Das ist sehr klein, allerdings ist das auch notwendig bei einer RAM Größe von 256kb und einem Archivspeicher von 2.5mb, wovon 1.5mb nutzbar sind.

    Im ROM ist printf nicht vorhanden. Der TI200 hat im Rom primitivere Funktionen gespeichert, wie z.B. DrawStr(...) um Strings auszugeben oder DrawChar(...) für ein einzelnes Zeichen.

    Die printf Funktion ist erst aus den verschiedenen Rom-Funktionen zusammengebastelt worden.
    Wenn man nun nur eine einfache Aufgabe zu lösen hat, so ist es besser, man verwendet eine eigene Funktion als (s)printf(), weil man damit doch sehr viel Speicher spart.

    Wenns interessiert: http://tigcc.ticalc.org/

    Grüße,
    Harri


Anmelden zum Antworten