Addition für ver. OS



  • Aufgabe:

    Entwickeln Sie eine C++-Anwendung, die den Anwender zur Eingabe zweier Ganzzahlen auffordert. Die beiden eingegebenen Zahlen sollen mit Hilfe einer Funktion addiert werden, die gleichzeitig die Summe auf den Bildschirm ausgibt. Das Programm soll auf den drei fiktiven Betriebssystemen Kuhnix BSE, Luxus und SinkOS 95 lauffähig sein. Kuhnix BSE bietet jedoch nur den Datentyp long an, um Ganzzahlen zu speichern. Luxus hingegen kennt nur den Datentyp char. Und SinkOS 95 kann Ganzzahlen nur in Variablen vom Typ short speichern. Verwenden Sie Präprozessor-Anweisungen in der Art, dass das Programm mit einer entsprechenden #define Anweisung jeweils so übersetzt wird, dass es unter dem jeweiligen Betriebssystem funktioniert. Falls das Programm unter dem nicht unterstützten Betriebssystem Banana Mac kompiliert wird, soll eine Fehlermeldung ausgegeben und die Kompilierung abgebrochen werden.

    Mein Quellcode:

    #include <iostream>
    using namespace std;
    
    void addition
    (
    	#if (__kuhnixbse__)
    	long a, long b
    	#elif (__luxus__)
    	char a, char b
    	#elif (__sinkos95__)
    	short a, short b
    	#elif (__bananamac__)
    	#error Betriebsystem wird nicht unterstuetzt!
    	#endif
    )
    {
    	a = a + b;
    	cout << "Ergebniss:\n";
    	cout << a << endl;
    }
    int main()
    {
    	#if (__kuhnixbse__)
    	long a, b;
    	#elif (__luxus__)
    	char a, b;
    	#elif (__sinkos95__)
    	short a, b;
    	#endif
    
    	cout << "Nennen sie bitte zwei Zahlen!\n";
    	cout << "1.Zahl:\n";
    	cin >> a;
    	cout << "2.Zahl:\n";
    	cin >> b;
    	addition (a, b);
    }
    

    2Probleme habe ich:
    -bei (__bananamac__) wird das compilieren nicht abgebrochen.
    -ich bekomme es nicht hin, in char mehr als 1Ziffe zu speichern. 😞



  • Hallo,
    erstmal würde ich den Code so umschreiben, dass du die Präprozessor-Anweisungen nur einmal brauchst. Da hilft die sprichwörtliche Indirektion: du definierst einen neuen Typen IntType, als Typedef auf einen vorhandenen Typ. Welcher Typ benutzt wird, machst du abhängig vom BS:

    #if defined(__kuhnixbse__)
    typedef long IntType;
    #elif defined(__luxus__)
    typedef char IntType;
    #elif defined(__sinkos95__)
    typedef short IntType;
    #elif defined(__bananamac__)
    #error Betriebsystem wird nicht unterstuetzt!
    #else
    #error Kein BS definiert
    #endif
    

    Jetzt kannst du sowohl in addition, als auch in main IntType verwenden:

    void addition(IntType a, IntType b)
    {
        a = a + b;
        cout << "Ergebniss:\n";
        cout << a << endl;
    }
    int main()
    {
        IntType a, b;   
        cout << "Nennen sie bitte zwei Zahlen!\n";
        cout << "1.Zahl:\n";
        cin >> a;
        cout << "2.Zahl:\n";
        cin >> b;
        addition (a, b);
    }
    

    -ich bekomme es nicht hin, in char mehr als 1Ziffe zu speichern

    Das Problem liegt nur an der Ausgabe. cout interpretiert ein char immer als einzelnes Zeichen. Wenn du also 10 + 20 rechnest und dann das Ergebnis 30 ausgiebst, wird nicht die Zahl 30 sondern der Buchstabe mit dem ASCII-Wert 30 ausgegeben. Umgehen kannst du das auf verschiedenen Wegen:
    einer wäre z.B. ein Cast nach int:

    cout << static_cast<int>(a) << endl;
    


  • HumeSikkins schrieb:

    Das Problem liegt nur an der Ausgabe.

    Das stimmt nicht. In eine char-Variable wird mit cin nur der ASCII-Wert des ersten Zeichens eingelesen.



  • Ich würde die Ein-/Ausgabe einfach mit scanf und printf machen. cstdio ist ja im C++ standard drinnen. Wenn Luxus nur den typ char kennt, darfst du ja außerdem wahrscheinlich gar nicht nach int casten.



  • winheis schrieb:

    HumeSikkins schrieb:

    Das Problem liegt nur an der Ausgabe.

    Das stimmt nicht. In eine char-Variable wird mit cin nur der ASCII-Wert des ersten Zeichens eingelesen.

    Da hast du natürlich recht.

    Ich würde die Ein-/Ausgabe einfach mit scanf und printf machen. cstdio ist ja im C++ standard drinnen. Wenn Luxus nur den typ char kennt, darfst du ja außerdem wahrscheinlich gar nicht nach int casten.

    Inwieweit hilft das? scanf verhält sich hier genau wie cin. Es sei denn du änderst den Format-Specifier. Das führt dann aber zu undefiniertem Verhalten, weil ein %d z.B. einen Pointer auf int erwartet keinen Pointer auf char.
    Oder übersehe ich hier gerade etwas?



  • winheis schrieb:

    Ich würde die Ein-/Ausgabe einfach mit scanf und printf machen. cstdio ist ja im C++ standard drinnen. Wenn Luxus nur den typ char kennt, darfst du ja außerdem wahrscheinlich gar nicht nach int casten.

    So sieht es aus. 🙂
    Aber wie meinst du das mit scanf/printf?
    Hatte bisher sowas noch nicht.

    kurze aktualisation des Quelltextes:

    #include <iostream>
    using namespace std;
    
        #if (__kuhnixbse__)
    	typedef long IntType;
    	#elif (__luxus__)
    	typedef char IntType;
    	#elif (__sinkos95__)
    	typedef short IntType;
    	#elif (__bananamac__)
    	#error Betriebsystem wird nicht unterstuetzt!
    	#else
    	#error Betriebsystem wurde nicht gefunden werden!
    	#endif
    
    void addition(IntType a, IntType b)
    {
    	a = a + b;
    	cout << "Ergebniss:\n";
    	cout << static_cast<int>(a) << endl;
    }
    int main()
    {	
    	IntType a, b;
    	cout << "Nennen sie bitte zwei Zahlen!\n";
    	cout << "1.Zahl:\n";
    	cin >> a;
    	cout << "2.Zahl:\n";
    	cin >> b;
    	addition (a, b);
    }
    


  • @HumeSikkins: Dass %d scanf dazu veranlasst einen Pointer auf int zu erwarten, habe ich gar nicht bedacht. Im Normalfall scheinst du Recht zu haben. Ich habe mehrmals folgenden Test durchgeführt, um über die char-Variable hinauszulesen und zu überprüfen, ob mittels scanf dort hingeschrieben wurde:

    #include <cstdio>
    using namespace std;
    
    int main()
    {
        char foo;
        scanf("%d", &foo);    
        printf("%d", (*((int*)(void*)&foo))); //Don't try this at home!!!
    }
    

    Glücklicherweise hat es ohne Absturz funktioniert, und ich konnte jedesmal beobachten, dass scanf tatsächlich über den Speicherbereich der char-Variablen foo hinausschreibt. Ich würde es trotzdem für das fiktive Luxus so machen und es damit rechtfertigen, dass char ja der Zahlentyp für Luxus sei und scanf beim Format-Specifier %d auf das jeweilige BS abgestimmt sein müsse.



  • Über den Umweg (void*) muss man noch nicht mal gehen, um diesen fiesen Test zu machen.

    printf("%d", (*((int*)&foo)));//Don't try this at home!!!
    

    Ich habe wohl zu wenig mit Zeigerverbiegerei zu tun.



  • Es könnte so aussehen:

    #include <cstdio>
    
    #if defined(__kuhnixbse__)
    typedef long IntType;
    #elif defined(__luxus__)
    typedef char IntType;
    #elif defined(__sinkos95__)
    typedef short IntType;
    #elif defined(__bananamac__)
    #error Betriebsystem wird nicht unterstuetzt!
    #else
    #error Betriebsystem konnte nicht gefunden werden!
    #endif
    
    int main()
    {
        IntType a, b;
        printf("Nennen sie bitte zwei Zahlen!\n1.Zahl:");
        scanf("%d", &a);
        printf("2.Zahl:");
        scanf("%d", &b);
        printf("\Addition: %d", a+b);
    }
    

    ACHTUNG ⚠ Beim Testen mit Luxus kommt eventuell (bei mir war es bis jetzt immer der Fall) Mist raus, weil der Speicherbereich von a durch das zweite scanf überschrieben wird! Falls man Luxus installiert hätte, sollte das aber nicht der Fall sein. Andererseits könnte man aber auch argumentieren cin und cout müssten bei Luxus für char einem Zahlentyp entsprechend implementiert sein. Daher ist die Lösung mit <iostream> wohl doch vorzuziehen. Insbesondere, wenn ihr gar kein scanf/printf besprochen habt!



  • Hm, das sind Befehle die ich leider noch nicht hatte.
    Aber danke für die Antworten, dadurch weiß ich wenigstens, das es nicht so einfach möglich ist. 🙂



  • Argumentiere, dass auf Luxus cin/cout char als Zahlentyp interpretieren müsste. Höchstwahrscheinlich ging es bei der Übung ausschließlich um bedingte Kompilierung!



  • @winheis
    Eine legale Alternative wäre das zeilenweise Einlesen mit anschließender Umwandlung der Zeichen in eine Zahl. Ganz grob:

    char readCharAsInt() {
    
    	char temp[std::numeric_limits<char>::digits10 + 2];
    	int maxExp = 1;
    	for (int i = 0; i != std::numeric_limits<char>::digits10; ++i) {
    		maxExp *= 10;
    	}
    
    	cin.getline(temp, sizeof(temp));
    
    	int i = cin.gcount() - 1;
    	int j = 0;
    	char res = 0;
    	while (i != 0) {
    		--i;
    		res += (temp[j++] - '0')* maxExp;
    		maxExp /= 10;
    	}
    	return res;
    }
    

    Das wird natürlich deutlich komplizierter, wenn man auch negative Zahlen, Overflow/Underflow, Fehleingaben usw. berücksichtigen möchte.


Anmelden zum Antworten