Eigener Datentyp int ab 1, (Bitshift, Konversion), limits(.h) mit C++98 und Linux



  • Einführung:

    Um den Code intuitiver verstehbar zu machen und nicht bei jeder Variablen 1 oder 2 Byte zu verschwenden,
    hätte ich gern hätte ich einen Datentyp unsigned short int und unsigned long int,
    welcher die positiven ganzen Zahlen, also ohne die 0, beinhaltet.
    Selbst wenn es geringfügig mehr Rechenaufwand bedeuten sollte.

    Das ursprünglich gedachte C++-Modell umgehe ich oft ungern,
    da ich die aufblähung des Codes und somit wahrscheinlich auch des Programms
    vermeiden und auch einen möglicht leicht nachvollziehbaren Quelltext schreiben möchte.
    Daher definiere ich zunächst nur Opperatorfunktionen, welche ich brauche.

    Vorerst schließt dies beispielsweise globale Opperatorfunktionen,
    zur Ermöglichung der Vertauschbarkeit von Opperanden aus.

    Falls es sich lohnt
    kann ich zusätzlich zu den Konvertierenden Konstruktoren noch
    sepatate Opperatorfunktionen für jeden gebrauchten Datentyp hinzufügen,
    damit Laufzeit und der Speicherplatz
    zur Erstellung von temporären Objekten gespart wird.

    Ich schreibe hier also nicht direkt eine universelle Klasse.
    Wenn es soetwas allerdings schon gibt würde ich mich auf einen Hinweis freuen.

    Auf Exception-Handling verzichte ich in dem Beispiel. Dies aufgrund dem
    erhöhten Laufzeitbedarf. Zudem soll das Programm in den meisten Fällen
    auch bei zeitweiser Produktion von Datenmüll weiterlaufen.
    Fehlermeldungen werden hier zur Sichtung auf der Konsole ausgegeben.

    Fehler:

    Der Bitshift Operator "<<" produziert den Fehler:
    [C++ Fehler] Unit1.cpp(8): E2094 'operator<<' ist im Typ 'ostream' für Argumente des Typs 'Spo' nicht implementiert

    Bei Iteratorverwendung (im Test mit advance) gibt es den Fehler:
    [C++ Fehler] _iterator_base.h(434): E2096 Ungültige Strukturoperation
    Dies bezüglich _iterator_base.h der bei:
    `if (__n > 0)

    while (__n--) ++__i;

    else

    while (__n++) --__i;Wenn diesbezüglich die benutzerdefinierte KonversionSpo::operator int() const` definiert ist, gibt es die Fehler:
    [C++ Fehler] Unit1.cpp(17): E2015 Mehrdeutigkeit zwischen 'Spo::operator -(const Spo &) const' und 'Spo::operator int() const'
    [C++ Fehler] Unit1.cpp(17): E2285 Keine Übereinstimmung für 'advance<_InputIterator,_Distance>

    Mit Linux g++ gibt es bei Verwendung von limits(.h) und C++98 den Fehler:
    error: 'USHRT_MAX' was not declared in this scope
    Die auf http://stackoverflow.com/questions/3233054/error-int32-max-was-not-declared-in-this-scope
    zum Datentyp int32 vorgeschlagene Lösung der Einbindung von #define __STDC_LIMIT_MACROS
    war ohne Wirkung.

    Ich würde mich freuen, wenn da jemand etwas wüsste.

    Codebeispiel:

    Unit1.cpp:

    #pragma hdrstop              // Wird mit Linux g++ ignoriert
    #include "Unit2.h"
    int main(int argc, char* argv[])
      {
      list<bool> lst;
      lst.push_back();
      lst.push_back();
      list<bool>::iterator i=lst.begin();
      ++i;
      Spo s1;
      s1=2;
      //int iii=s1;
      //cout << s1 << endl;       // [C++ Fehler] Unit1.cpp(8):
      cout << USHRT_MAX << endl;  //   E2094 'operator<<' ist im Typ 'ostream' für Argumente des Typs 'Spo' nicht implementiert
      cout << s1.GetInt() << endl;
      s1.operator<<(cout);
      //advance(i, s1-1);         // [C++ Fehler] _iterator_base.h(434): E2096 Ungültige Strukturoperation
                                  //   bei:
                                  //     if (__n > 0)
                                  //       while (__n--) ++__i;
                                  //     else
                                  //       while (__n++) --__i;
      i=lst.begin();
      advance(i, s1.GetInt()-1);
    
      cin.get();                    // Dummyinput for keeping the console window open.
      return 0;
      }
    

    Unit2.cpp:

    #pragma hdrstop              // Wird mit Linux g++ ignoriert
    #include "Unit2.h"
    #pragma package(smart_init)  // Wird mit Linux g++ ignoriert
    
    Spo::Spo()
      {
      m_spo = new unsigned short int;
      }
    
    Spo::Spo(unsigned short int spo)
      {
      m_spo = new unsigned short int(spo-1);
      }
    
    Spo::~Spo()
      {
      delete m_spo;
      }
    
    Spo &Spo::operator=(const Spo &b)
      {
      *m_spo = *b.m_spo;
      return *this;
      }
    
    Spo &Spo::operator++()
      {
      if (*m_spo!=USI_MAX)
        ++*m_spo;
      else
        cout << "Fehler: Element vom Typ Spo hat bereits den höchsten Wert -> Nicht inkrementiert" << endl;
      return *this;
      }
    
    Spo &Spo::operator++(int praefix)
      {
      return ++*this;
      }
    
    Spo &Spo::operator--()
      {
      if (*m_spo!=USI_MIN)
        --*m_spo;
      else
        cout << "Fehler: Element vom Typ Spo hat bereits den niedrigsten Wert -> Nicht dekrementiert" << endl;
      return *this;
      }
    
    Spo &Spo::operator--(int praefix)
      {
      return --*this;
      }
    
    Spo Spo::operator+(const Spo &b) const
      {
      return Spo((*m_spo+1)+(*b.m_spo+1));  // m_spo has an offset of -1
      }
    
    Spo Spo::operator-(const Spo &b) const
      {
      return Spo((*m_spo+1)-(*b.m_spo+1));
      }
    
    Spo Spo::operator*(const Spo &b) const
      {
      return Spo((*m_spo+1)*(*b.m_spo+1));
      }
    
    Spo Spo::operator/(const Spo &b) const
      {
      return Spo((*m_spo+1)/(*b.m_spo+1));
      }
    
    bool Spo::operator==(const Spo &b) const
      {
      if (*m_spo==*b.m_spo)
        return true;
      else
        return false;
      }
    
    bool Spo::operator!=(const Spo &b) const
      {
      return !(*this==b);
      }
    
    bool Spo::operator<(const Spo &b) const
      {
      return *m_spo<*b.m_spo;
      }
    
    bool Spo::operator>(const Spo &b) const
      {
      return b<*this;
      }
    
    bool Spo::operator<=(const Spo &b) const
      {
      return !(*this>b);
      }
    
    bool Spo::operator>=(const Spo &b) const
      {
      return !(*this<b);
      }
    
    ostream &Spo::operator<<(ostream &os) const
      {
      return os << *m_spo+1;
      }
    
    int Spo::GetInt() const
      {
      return *m_spo+1;
      }
    
    //Spo::operator int() const  // Bei advance: [C++ Fehler] Unit1.cpp(17): E2015 Mehrdeutigkeit zwischen 'Spo::operator -(const Spo &) const' und 'Spo::operator int() const'
    //  {                        //              [C++ Fehler] Unit1.cpp(17): E2285 Keine Übereinstimmung für 'advance<_InputIterator,_Distance>(_List_iterator<bool,_Nonconst_traits<bool> >,undefined)' gefunden
    //  return *m_spo+1;
    //  }
    

    Unit2.h:

    #ifndef Unit2H
    #define Unit2H
    
    #include <iostream>  // Operator overloading, (cout)
    #define __STDC_LIMIT_MACROS  // Empfehlung zur Problembehebung in Linux leider wirkungslos
    #include <limits>
    #include <list>
    using namespace std;
    
    const unsigned short int USI_MIN=0;  // USI = unsigned short int
    const unsigned short int USI_MAX=USHRT_MAX;
    
    class Spo  // ShortPos positive unsigned short int
      {
      unsigned short int* m_spo;
     public:
      Spo();
      Spo(unsigned short int spo);
      ~Spo();
      Spo &operator=(const Spo &b);
      Spo &operator++();
      Spo &operator++(int praefix);
      Spo &operator--();
      Spo &operator--(int praefix);
      Spo operator+(const Spo &b) const;
      Spo operator-(const Spo &b) const;
      Spo operator*(const Spo &b) const;
      Spo operator/(const Spo &b) const;
      bool operator==(const Spo &b) const;
      bool operator!=(const Spo &b) const;
      bool operator<(const Spo &b) const;
      bool operator>(const Spo &b) const;
      bool operator<=(const Spo &b) const;
      bool operator>=(const Spo &b) const;
      ostream &operator<<(ostream &os) const;  //
      //operator int() const;
      int GetInt() const;
      };
    
    class Lpo  // LongPos positive unsigned (long) int
      {
      unsigned long int* m_lpo;
      };
    
    #endif
    


  • Der Operator << wird sinnvollerweise nicht als Memberfunktion implementiert.

    Also:

    ostream& operator<<(ostream& os, const Spo& spo) {
      // a) os << spo.irgendwas();
      // b) spo.print(os);
      return os;
    }
    

    Bei a) muss der operator<< gegebenenfalls als friend deklariert werden.
    Wobei b) den Vorteil hat, dass man es immer so machen kann und ein virtuelles print möglich wird. (hier muss dann noch die Methode print implementiert werden)

    Ansonsten stelle ich mir aber die Frage, was das ganze soll. Trollerei? Weshalb kannst du durch Weglassen der 0 ein Byte sparen? Und vor allem: dein Spo enthält doch einen Pointer -> das ist also doch dann insgesamt ein Bedarf von Pointergröße+int-Größe. Erscheint mir also erstmal schwachsinnig zu sein. Deine Rechnungen habe ich sicherheitshalber gar nicht näher angesehen.


Log in to reply