Die C++ Programmiersprache - Hilfe zu Fragestellungen?



  • Hey Leute,
    ich hoffe ihr könnt mir vlt. helfen. Ich versuche mich gerade in C++ neu einzuarbeiten und habe mir diesmal das o.g. Buch als Übungswerk vorgenommen.

    Nun gibt es dort folgende Aufgabe:

    "Was sind auf ihrem System die Beschränkungen für die Zeiger-typen char*, int*, void?
    Kann beispielsweise ein int* einen ungeraden Wert haben? Tip: Ausrichtung?"

    • Die C++ Programmiersprache, 4. Auflage, S.113

    Ich verstehe nicht genau was dort von mir verlangt wird, bezieht sich das auf Zeigerarithmetik?
    Habe nun Zieger initialisiert und diese von einander abgezogen. Habe aber keine Ahnung ob das überhaupt richtig ist 😱

    folgenden Code habe ich geschrieben:

    int main()
    {
    	int zahl1 = 1;
    	int zahl2 = 2;
    	int* ptr_zahl1 = &zahl1; //0x008ffdac
    	int* ptr_zahl2 = &zahl2; //0x008ffda0
    	int size_int = ptr_zahl1 - ptr_zahl2; // Ausgabe: 3
    	int size_int2 = ptr_zahl2 - ptr_zahl1; // Ausgabe: -3
    
    	char buchstabe1 = 'a';
    	char buchstabe2 = 'b';
    	char* ptr_buchstabe1 = &buchstabe1; //0x008ffd67
    	char* ptr_buchstabe2 = &buchstabe2; //0x008ffd5b
    	int size_char1 = ptr_buchstabe1 - ptr_buchstabe2; // Ausgabe: 12
    	int size_char2 = ptr_buchstabe2 - ptr_buchstabe1; // Ausgabe: -12
    
    	//bei void Zeigern wüsste ich nicht mal was ich dort machen müsste?
    	
    	return 0;
    }
    
    

    Ich hoffe ihr könnt mir vlt. helfen?

    Viele Grüße
    cnc13


  • Mod

    Vermutlich ist so etwas in dieser Art gemeint:

    #include <iostream>
    #include <cstddef>
    using namespace std;
    
    int main() 
    {
    	int i = 0;
    	int *p = &i;
    	cout << "p ist " << p << '\n';
    	cout << "p+1 ist " << p+1 << '\n';
    	cout << "Das ist ein Unterschied von " << reinterpret_cast<intptr_t>(p+1) -  reinterpret_cast<intptr_t>(p) << '\n';
    }
    

    Mögliche Ausgabe:

    p ist 0x7ffe99822374
    p+1 ist 0x7ffe99822378
    Das ist ein Unterschied von 4
    

    Wonach man dann mindestens weiß, dass gerade Werte möglich sind. Und man kann vermuten, dass es immer Vielfache von 4 sein müssen, weil man nach ein paar Versuchen immer sieht, dass es Vielfache von 4 sind, und man vielleicht etwas darüber gelesen hat, dass das ein übliches Verhalten ist. Wirklich wissen kann man es danach aber nicht.

    In neueren C++-Versionen kann man es wissen, da man direkt den Compiler fragen kann:

    #include <iostream>
    using namespace std;
    
    int main() 
    {
    	cout << "Alignment von int: " << alignof(int) << '\n';
    }
    

    (Was dann oft 4 ausgeben wird)


  • Mod

    PS: Wenn man sich für ganz schlau hält, kann man natürlich noch den Standard lesen. Wo unter anderem drin steht, dass das Alignment der char-Typen immer 1 sein muss. Woraus auch folgt, dass ein void* alle Werte annehmen kann, da der Standard auch garantiert, dass man jeden (normalen) Pointer zu void* und wieder zurück casten kann, und das gleiche Ergebnis erhalten muss wie den Anfangswert.



  • Man darf aber gerade beo solchen Sachen nicht von dem Verhalten eines Compilers auf einem System auf andere Compiler/Systeme schließen.

    Es gibt/gab (exotische) (DSP-)Systeme, dort ist ein Byte 24-Bit breit. Das ist die kleinste adressierbare Einheit.
    Dort sind dann char, short und int gleich groß.



  • @SeppJ sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    #include <iostream>
    #include <cstddef>
    using namespace std;

    int main()
    {
    int i = 0;
    int *p = &i;
    cout << "p ist " << p << '\n';
    cout << "p+1 ist " << p+1 << '\n';
    cout << "Das ist ein Unterschied von " << reinterpret_cast<intptr_t>(p+1) - reinterpret_cast<intptr_t>(p) << '\n';
    }

    Okay, das hat mir was geholfen 🙂
    Also könnte damit einfach gemeint sein, dass man herausfinden soll welche Größe bsp. ein int im speicher belegt?

    Wenns das ist, ist das aber schon echt eine umständliche art, Bsp.. der sizeof() Operator liefert einen doch auch die Größen von char und ints etc.?😀

    Das einzige was ich noch nicht ganz verstanden habe sind die void* . Welchen Zweck haben die und wie soll man die initialisieren?


  • Mod

    Unwahrscheinlich. Die Größe eines ints wäre viel einfacher:sizeof(int)

    Es geht wahrscheinlich wirklich darum, dass du verstehst, was Alignment ist. Auch wenn ich das für eine relativ nutzlose Information für einen Anfänger halte. Das wird dir im realen C++-Leben niemals begegnen, außer du programmierst eigene Betriebssysteme oder ähnliches. Eventuell auch, wenn du Spezialfunktionen einer CPU manuell aufrufst (z.B. bevor die meisten Compiler SSE unterstützten, musste man das selber programmieren, und SSE hat recht harte Alignmentanforderungen)

    Alignment ist auch eines der Gründe, warum wildes Pointergefrickel gefährlich sein kann. Aber da wildes Pointergefrickel noch aus viel besseren Gründen zu unterlassen ist, ist das Alignment auch da nicht so wichtig,



  • @SeppJ

    Okay:)
    align bedeutet übersetzt auch Ausrichtung, also schätze ich mal das das auch gefordert war. 🙂

    Vielen Dank, hat mir auf jeden Fall geholfen 🙂


  • Mod

    @cnc13 sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    @SeppJ

    Okay:)
    align bedeutet übersetzt auch Ausrichtung, also schätze ich mal das das auch gefordert war. 🙂

    Vielen Dank, hat mir auf jeden Fall geholfen 🙂

    Huh? Ach, so war das gemeint: Du sollst anscheinend selber drauf kommen, indem du dir die Pointerwerte anguckst, dass es so etwas wie Alignment gibt.
    Da wir es ja nun schon so gut wie verraten haben: Die ganzen Basisdatentypen sind ziemlich nahe an der Hardware, der CPU, des Computers. Die werden davon direkt unterstützt. Aber die CPU hat oft auch gewisse Anforderungen daran, wie diese Werte im Speicher liegen müssen, damit sie sie effizient (oder überhaupt) verarbeiten kann. Das liegt einfach daran, wie übliche Computer intern verdrahtet sind. Das ist das Alignment - die Ausrichtung - die von diesen Datentypen verlangt wird. Wie du gesehen hast, haben int oft ein Alignment von 4, das heißt die Adresse muss durch 4 teilbar sein, damit die CPU einen Wert wie einen int verarbeiten kann.

    Übliche Alignments auf verbreiteten Systemen sind 1, 2, 4, und 8. Meistens ist das Alignment auch gleich der Größe des Datentyps. Oder bei zusammengesetzten Datentypen ist es gleich dem Alignments des ersten Unterdatentyps. Aber manchmal gibt es auch Spezialanforderungen, beispielsweise muss man Daten mit Alignment 16 speichern, wenn man die SSE-Anweisungen von x86-Prozessoren benutzen will.



  • @SeppJ sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    @cnc13 sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    @SeppJ

    Okay:)
    align bedeutet übersetzt auch Ausrichtung, also schätze ich mal das das auch gefordert war. 🙂

    Vielen Dank, hat mir auf jeden Fall geholfen 🙂

    Huh? Ach, so war das gemeint: Du sollst anscheinend selber drauf kommen, indem du dir die Pointerwerte anguckst, dass es so etwas wie Alignment gibt.
    Da wir es ja nun schon so gut wie verraten haben: Die ganzen Basisdatentypen sind ziemlich nahe an der Hardware, der CPU, des Computers. Die werden davon direkt unterstützt. Aber die CPU hat oft auch gewisse Anforderungen daran, wie diese Werte im Speicher liegen müssen, damit sie sie effizient (oder überhaupt) verarbeiten kann. Das liegt einfach daran, wie übliche Computer intern verdrahtet sind. Das ist das Alignment - die Ausrichtung - die von diesen Datentypen verlangt wird. Wie du gesehen hast, haben int oft ein Alignment von 4, das heißt die Adresse muss durch 4 teilbar sein, damit die CPU einen Wert wie einen int verarbeiten kann.

    Übliche Alignments auf verbreiteten Systemen sind 1, 2, 4, und 8. Meistens ist das Alignment auch gleich der Größe des Datentyps. Oder bei zusammengesetzten Datentypen ist es gleich dem Alignments des ersten Unterdatentyps. Aber manchmal gibt es auch Spezialanforderungen, beispielsweise muss man Daten mit Alignment 16 speichern, wenn man die SSE-Anweisungen von x86-Prozessoren benutzen will.

    Also lässt sich daraus auch annehmen, das die Ausrichtung nicht ungerade sein können, da ein Rechner in der Regel Daten verarbeitet zur Basis 2, oder gibt es Systeme die eine Ungerade Ausrichtung besitzen?


  • Mod

    @cnc13 sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    Also lässt sich daraus auch annehmen, das die Ausrichtung nicht ungerade sein können, da ein Rechner in der Regel Daten verarbeitet zur Basis 2, oder gibt es Systeme die eine Ungerade Ausrichtung besitzen?

    Nun, wie gesagt haben char gewöhnlich eine Ausrichtung von 1 (wäre auch ungünstig wenn nicht). Aber ansonsten: Ja. Alle Basisdatentypen haben gewöhnlich die Größe einer Zweierpotenz (nun, 1 ist auch eine Zweitpotenz, wenn man es genau nimmt), und das hängt über mehrere Ecken damit zusammen, dass der Rechner auf Zweierbasis arbeitet.





  • @cnc13 sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    Also lässt sich daraus auch annehmen, das die Ausrichtung nicht ungerade sein können, da ein Rechner in der Regel Daten verarbeitet zur Basis 2, oder gibt es Systeme die eine Ungerade Ausrichtung besitzen?

    Das gab es alles schon. Wenn ich mich da an die Motorola 68000 Familie erinnere, da mussten auf dem 68000, 68010, 68012 die 16Bit shorts und 32Bit ints auf 16Bit Grenzen ausgerichtet sein, sonst gab es einen Crash. Beim 68020 hingegen konnten sie auf 8Bit Grenze ausgerichtet sein. Ich bin mir nicht mehr sicher, aber ich glaube auf geraden Adressen war es schneller. D.h. je nach Compilereinstellung variierte der erzeugte Code und das Padding.



  • @cnc13 sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    Also lässt sich daraus auch annehmen, das die Ausrichtung nicht ungerade sein können, da ein Rechner in der Regel Daten verarbeitet zur Basis 2, oder gibt es Systeme die eine Ungerade Ausrichtung besitzen?

    Man kann, wenn auf dem System ein miss aligned Zugriff erlaubt ist, dies über über gepackte struct realisieren.

    @DirkB sagte in Die C++ Programmiersprache - Hilfe zu Fragestellungen?:

    Es gibt/gab (exotische) (DSP-)Systeme, dort ist ein Byte 24-Bit breit. Das ist die kleinste adressierbare Einheit.
    Dort sind dann char, short und int gleich groß.

    und somit ist sizeof() davon 1 und können auf jeder Adresse liegen.