interne Bit Repräsentation eines int ausgeben



  • #include <stdio.h>
    #include <limits.h>
    
    int main(void)
    {
    	int Number = 0;
    	int NumberOfBits = sizeof(int) * CHAR_BIT;
    	unsigned int Bitmask = 1 << NumberOfBits - 1;
    
    	printf("Bitte geben sie eine Integer Zahl ein: ");
    	scanf("%d", &Number);
    
    	printf("/nDie Interne repraesentation als int Werte sieht wie folgt aus: ");
    
    	while(Bitmask)
    	{
    		Number & Bitmask ? printf("1") : printf("0");
    		Bitmask = Bitmask >> 1;
    	}
    }
    

    ich frage mich ob die Zeile:

    unsigned int Bitmask = 1 << NumberOfBits - 1;
    

    das macht was ich will - ich möchte das höchstwertige bit auf eins setzen - dazu gehe ich einfach aus das ein stink normals binärsystem verwendet wird - was wahrscheinlich auch so sein wird, aber mir nach C99 doch nicht garantiert ist - oder?

    wie bekomme ich Standardkonform das höchstwertige Bit auf 1 gesetzt und den Rest auf 0?



  • Vertexwahn schrieb:

    wie bekomme ich Standardkonform das höchstwertige Bit auf 1 gesetzt und den Rest auf 0?

    #include <limits.h>
    #include <stdio.h>
    
    typedef unsigned char Byte;
    typedef unsigned int  UInt;
    
    const UInt UInt_BitSize     = CHAR_BIT * sizeof(UInt);
    const UInt UInt_HighBit_Pos = UInt_BitSize - 1U;
    const UInt UInt_HighBit_Msk = 1U << UInt_HighBit_Pos;
    const UInt UInt_Bytes       = sizeof(UInt);
    
    const Byte Byte_BitSize     = CHAR_BIT;
    const Byte Byte_HighBit_Pos = Byte_BitSize - 1U;
    const Byte Byte_HighBit_Msk = 1U << Byte_HighBit_Pos;
    
    #pragma pack(1)
    typedef union __UInt_Word {
       UInt  uint_val;
       Byte  byte_val[ UInt_Bytes ];
    } UInt_Word;
    #pragma pack()
    
    void Byte_PrintBin( Byte val ) {
       for ( Byte i = Byte_HighBit_Msk; i != 0U; i >>= 1U ) {
          if ( val & i ) putchar( '1' ); else putchar( '0' );
       }
    }
    
    void UInt_PrintBin( UInt val ) {
       for ( UInt i = UInt_HighBit_Msk; i != 0U; i >>= 1U ) {
          if ( val & i ) putchar( '1' ); else putchar( '0' );
       }
    }
    
    void UInt_Word_Print_Hex( const UInt_Word* w ) {
       for ( UInt i=0; i != UInt_Bytes; ++i ) {
          printf( "%02X ", w->byte_val[i] );
       } 
    }
    
    void UInt_Word_Print_Bin( const UInt_Word* w ) {
       for ( UInt i=0; i != UInt_Bytes; ++i ) {
          Byte_PrintBin( w->byte_val[i] ); putchar( ' ' );      
       } 
    }
    
    void func( void ) {
       UInt highval = UInt_HighBit_Msk; UInt_Word w;
       printf( "UInt_BitSize     = %u\n", UInt_BitSize     );
       printf( "UInt_HighBit_Pos = %u\n", UInt_HighBit_Pos );
       printf( "UInt_HighBit_Msk = %u\n", UInt_HighBit_Msk );
       printf( "highval          = %u\n", highval          );
       printf( "highval (binaer) = " ); UInt_PrintBin( highval ); 
       putchar( '\n' ); fflush(stdout);
       w.uint_val = highval;
       printf( "highval (in mem, hex) = " ); UInt_Print_Word_Hex( &w ); 
       putchar( '\n' ); fflush(stdout);
       printf( "highval (in mem, bin) = " ); UInt_Print_Word_Bin( &w );
       putchar( '\n' ); fflush(stdout);
    }
    
    int main( int argc, char** argv ) { func(); return 0; }
    

    An diesem Programm kannst Du sehen, wie die Daten auf Deinem Rechner im Speicher abgelegt werden.

    Die Byte-Reihenfolge im Speicher muss nicht unbedingt mit der erwarteten Reihenfolge uebereinstimmen. Das haengt vom Prozessor ab.

    Einige Prozessoren speichern 32-Bit Werte im MSB..LSB Format ab (Motorola MC680x0, PPC), andere im LSB..MSB Format (Intel IA-32, AMD IA-32).



  • Bitmask&=0x00000000;    //Alles auf null
    Bitmask|=0x80000000;    //Letzte Bit in dem Fall das 32ste auf eins!
    

    meinst du so???

    mfg hohesC



  • Hi,

    scheint mir etwas zu komplex zu sein:

    #include <stdio.h>
    
    int bit(int zahl){
        if(zahl < 1)
                return 0;
        else
        {   
                printf("%i",zahl % 2);
                zahl = zahl / 2;
                bit(zahl);          
        }
    }
    
    int main()
    {
        bit(238);
        return 0;
    
    }
    


  • CarstenJ schrieb:

    scheint mir etwas zu komplex zu sein:

    ich wollte ein Programm programmieren, das die Interne Bit Darstellung eines int ausgibt - dafür gibts aber verschiedene Formate und dein Ansatz (die umwanldung in eine Binärzahl) gibt mir nicht die Umgebungsspezifische Anordungen eines int wieder

    hohesC schrieb:

    Bitmask&=0x00000000; //Alles auf null

    0x bedeutet für den Compiler, dass das folgende als Hexazahl zu interpretieren ist - genauso kann ich Schreiben Bitmask&=0;

    woher will ich wissen das die interne Bit Repräsentation für die Null aus lauter Nullen besteht - nur weil das im 2er Komplement so üblich ist - schreibt da der Standard etwas vor?

    hohesC schrieb:

    Bitmask|=0x80000000; //Letzte Bit in dem Fall das 32ste auf eins!

    vielleicht hat mein int auf meinem System 128 Bit - der Standard schreibt da nichts vor

    auserdem passt 0x80000000 nicht in einen 32 Bit Integer rein - nach Standard C99 wird jede Konstante die größer ist wie als int erlaubt als long interpretiert - was passiert wenn ich den Long Wert einem Int Wert zuweise? -nö da gibts vielle problemchen

    Power Off schrieb:

    const Byte Byte_HighBit_Msk = 1U << Byte_HighBit_Pos;

    was ist 1U - steht das für unsigned int? hier hat man doch wieder das gleich Problem wie bei meinem Code - woher will man wissen das 1U falls unsigned int 8 Bit hätte zu 1000 0000 wird? intern könnte man die 1 doch auch z. B. so Darstellen 1111 1110 - dann hab ich ein Problem

    Das Byte Packing hab ich total vergessen

    Power Off schrieb:

    Einige Prozessoren speichern 32-Bit Werte im MSB..LSB Format ab (Motorola MC680x0, PPC), andere im LSB..MSB Format (Intel IA-32, AMD IA-32).

    Yup... es ist üblich, dass die bits von integer-datentypen in der umgekehrten reihenfolge abgelegt werden



  • Vertexwahn schrieb:

    Power Off schrieb:

    const Byte Byte_HighBit_Msk = 1U << Byte_HighBit_Pos;

    was ist 1U - steht das für unsigned int? hier hat man doch wieder das gleich Problem wie bei meinem Code - woher will man wissen das 1U falls unsigned int 8 Bit hätte zu 1000 0000 wird? intern könnte man die 1 doch auch z. B. so Darstellen 1111 1110 - dann hab ich ein Problem

    Ja, "1U" steht fuer unsigned int -- unsigned ints ermoeglichen es, auch das oberste Bit zu benutzen.

    Du rechnest ja bei der Binaerausgabe mit dem Inhalt der Variablen. D.h. egal, wie der Prozessor die Daten intern abbildet, die Funktion gibt immer dasselbe aus.

    An die genaue Bitdarstellung kommt man ueber C nicht dran, weil es keinen Bit-Datentyp gibt. Liest Du z.B. ein Byte, kann der Prozessor die Bits schon rumgedreht haben, bevor sie in Deinem Programm ankommen.

    Standardmaessig ist die Zahlendarstellung naemlich normiert. Anders als in BCPL, werden in C Bits immer von rechts gezaehlt (vom LSB aus). Ein Shift nach rechts ist in C immer eine Division durch 2, und ein Shift nach links immer eine Multiplikation mal 2.

    In BCPL gibt es das Problem, das Bitmasken und Bitshifts nicht portabel sind, da manche Prozessoren in der Tat die Bits andersrum abspeichern.

    Es gibt aber keinen mir bekannten Prozessor, der "1" als etwas anderes als "0000 0001" bzw. "1000 0000" ablegen wuerde.

    Vertexwahn schrieb:

    Das Byte Packing hab ich total vergessen

    Power Off schrieb:

    Einige Prozessoren speichern 32-Bit Werte im MSB..LSB Format ab (Motorola MC680x0, PPC), andere im LSB..MSB Format (Intel IA-32, AMD IA-32).

    Yup... es ist üblich, dass die bits von integer-datentypen in der umgekehrten reihenfolge abgelegt werden

    Mit MSB ... LSB meinte ich "Most Significant Byte" und "Least Significant Byte", also nur die Byte-Reihenfolge ist vertauscht, die Bit-Reihenfolge entspricht der Norm.

    Leider hat es sich bei Intel-Prozessoren eingebuergert, die Bytes verkehrt herum zu speichern, was auch seine Vorteile hat, leider sind Hexdumps dann schwerer zu lesen.

    Vorsicht bei der Verwendung der Begriffe "little endian" und "big endian". Motorola definierte die Begriffe urspruenglich so, dass sie sich auf das "LSB" und "MSB" bezogen (d.h. Motorola's Prozessoren waren "little endian" -- also das LSB wird zuletzt abgespeichert --, Intel's "big endian" -- das MSB wird zuletzt abgespeichert -- ), Intel definierte es so, dass es sich auf die Speicheradresse bezog (Intel's Prozessoren waren damit "little endian" -- das LSB steht auf der kleinsten Adresse --, Motorola's "big endian" -- das LSB steht auf der groessten Adresse -- ). Zwar hat sich die Intel-Definition mittlerweile eingebuergert, aber es ist trotzdem verwirrend. Besser ist es m.E., von LSB..MSB (bei Intel) bzw. MSB..LSB (bei Motorola) zu sprechen, weil die Anordnung dann klar ist.



  • Power Off schrieb:

    Es gibt aber keinen mir bekannten Prozessor, der "1" als etwas anderes als "0000 0001" bzw. "1000 0000" ablegen wuerde.

    angeblich soll es noch welche geben, die ein parity-bit mit abspeichern (also 9 bits pro byte). kenn ich aber auch nur vom hörensagen



  • #Standardmaessig ist die Zahlendarstellung naemlich normiert. Anders als in
    #BCPL, werden in C Bits immer von rechts gezaehlt (vom LSB aus). Ein Shift nach
    #rechts ist in C immer eine Division durch 2, und ein Shift nach links immer
    #eine Multiplikation mal 2.

    Der C Standard sagt zur Bitdarstellung nicht mehr als das es ein LSB und ein MSB gibt. Der Rest ist den Compilerbauern überlassen unter der Bedingung das ein Linkshift eine "Multiplikation" mit 2^Anzahl der zu shiftenden Bits^ und ein Rechtsshift eine "Division" mit 2^Anzahl der zu shiftenden Bits^ zu sein hat.

    #In BCPL gibt es das Problem, das Bitmasken und Bitshifts nicht portabel sind, da
    #manche Prozessoren in der Tat die Bits andersrum abspeichern.

    Das klingt so nach, ich kompiliere auf Maschine A mit Prozessor P1 und lasse auf auf Maschine mit Prozessor P2 laufen. Das das nich funktioniert wenn beide Prozessoren nicht die selbe Bauweise haben scheint einleuchtend.



  • TheTester schrieb:

    Der C Standard sagt zur Bitdarstellung nicht mehr als das es ein LSB und ein MSB gibt. Der Rest ist den Compilerbauern überlassen unter der Bedingung das ein Linkshift eine "Multiplikation" mit 2^Anzahl der zu shiftenden Bits^ und ein Rechtsshift eine "Division" mit 2^Anzahl der zu shiftenden Bits^ zu sein hat.

    Das reicht, um die Bitordnung festzulegen -- waere das LSB links, waere ein Linksshift eine Division und ein Rechtsshift eine Multiplikation. Da es aber andersum ist, muss das LSB rechts sein, klar?


Anmelden zum Antworten