C++ ungeeignet für 64K Demos?



  • volkard schrieb:

    .................. schrieb:

    Das ist doch kein Argument etwas anzufangen und halb fertig liegen lassen. Das ist eine Potenzielle Fehlerquelle!

    erhoffst du dir, daß ich eine fertige string-klasse baue? dazu hatte ich gerade keine lust.

    Das brauchst du auch nicht, mein Süßer. Das mach' ich schon für dich:

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    class String
    {
      public:
    	// Konstruktoren
    	String();
    	String(const char *const);
    	String(const String &);
    	~String();
    
    	// Überladene Operatoren
    	char & operator[](int offset);
    	char operator[](int offset) const;
    	String operator+(const String&);
    	void operator+=(const String&);
    	String & operator= (const String &);
    
    	// Allgemeine Zugriffsoperatoren
    	int GetLen()const { return itsLen; }
    	const char * GetString() const { return itsString; }
    	// static int ConstructorCount;
    
      private:
    	String (int);         // Privater Konstruktor
    	char * itsString;
    	int itsLen;
    
    };
    
    // Standardkonstruktor erzeugt String von 0 Bytes Länge
    String::String()
    {
    	itsString = new char[1];
    	itsString[0] = '\0';
    	itsLen=0;
    	// cout << "\tString-Standardkonstruktor\n";
    	// ConstructorCount++;
    }
    
    // Privater (Hilfs-) Konstruktor, nur von Klassen-
    // methoden zum Erzeugen eines neuen Strings der
    // erforderlichen Größe verwendet. Mit Null gefüllt.
    String::String(int len)
    {
    	itsString = new char[len+1];
    	int i;
    	for (i = 0; i<=len; i++)
    		itsString[i] = '\0';
    	itsLen=len;
    	// cout << "\tString(int)-Konstruktor \n";
    	// ConstructorCount++;
    }
    
    String::String(const char * const cString)
    {
    	itsLen = strlen(cString);
    	itsString = new char[itsLen+1];
    	int i;
    	for (i = 0; i<itsLen; i++)
    		itsString[i] = cString[i];
    	itsString[itsLen]='\0';
    	// cout << "\tString(char*)-Konstruktor\n";
    	// ConstructorCount++;
    }
    
    String::String (const String & rhs)
    {
    	itsLen=rhs.GetLen();
    	itsString = new char[itsLen+1];
    	int i;
    	for ( i = 0; i<itsLen;i++)
    		itsString[i] = rhs[i];
    	itsString[itsLen] = '\0';
    	// cout << "\tString(String&)-Konstruktor\n";
    	// ConstructorCount++;
    }
    
    String::~String ()
    {
    	delete [] itsString;
    	itsLen = 0;
    	// cout << "\tString-Destruktor\n";
    }
    
    // Gleich-Operator, gibt vorhandenen Speicher frei,
    // kopiert dann String und Größe
    String& String::operator=(const String & rhs)
    {
    	if (this == &rhs)
    		return *this;
    	delete [] itsString;
    	itsLen=rhs.GetLen();
    	itsString = new char[itsLen+1];
    	int i;
    	for (i = 0; i<itsLen;i++)
    		itsString[i] = rhs[i];
    	itsString[itsLen] = '\0';
    	return *this;
    	// cout << "\tString-Operator=\n";
    }
    
    // Nicht konstanter Offset-Operator, gibt Referenz
    // auf Zeichen zurück, das sich damit ändern
    // läßt!
    char & String::operator[](int offset)
    {
    	if (offset > itsLen)
    		return itsString[itsLen-1];
    	else
    		return itsString[offset];
    }
    
    // Konstanter Offset-Operator für konstante
    // Objekte (siehe Kopierkonstruktor!)
    char String::operator[](int offset) const
    {
    	if (offset > itsLen)
    		return itsString[itsLen-1];
    	else
    		return itsString[offset];
    }
    
    // Erzeugt einen neuen String durch Anfügen des
    // aktuellen Strings an rhs
    String String::operator+(const String& rhs)
    {
    	int  totalLen = itsLen + rhs.GetLen();
    	int i,j;
    	String temp(totalLen);
    	for (i = 0; i<itsLen; i++)
    		temp[i] = itsString[i];
    	for (j = 0; j<rhs.GetLen(); j++, i++)
    		temp[i] = rhs[j];
    	temp[totalLen]='\0';
    	return temp;
    }
    
    // Ändert aktuellen String, gibt nichts zurück
    void String::operator+=(const String& rhs)
    {
    	int rhsLen = rhs.GetLen();
    	int totalLen = itsLen + rhsLen;
    	int i,j;
    	String  temp(totalLen);
    	for (i = 0; i<itsLen; i++)
    		temp[i] = itsString[i];
    	for (j = 0; j<rhs.GetLen(); j++, i++)
    		temp[i] = rhs[i-itsLen];
    	temp[totalLen]='\0';
    	*this = temp;
    }
    
    // int String::ConstructorCount = 0;
    


  • bei mir bringt der überladene new operator weder vor noch nach dem upx'en etwas. 😞
    wobei ich für meine kleinen 64k demos bisher nie new benutzte und stringklassen emm.. naja... emm... wozu strings? hab ich auch noch nie benutzt.

    btw. sind bei 64k demos externe system-dlls die jeder haben sollte erlaubt, sonst wäre dx und oGL auch nicht zugelassen 🙂

    rapso->greets();



  • volkard schrieb:

    und wie sehen diese template-tricks aus?

    schattig. du mußt halt genau wissen, was du machst (auch immer wieder den erzeugten asm-code angucken, um ein gefühl dafür zu kriegen, was der compiler draus macht).

    Oh, da hab ich mich ein wenig vertan. Template-Tricks helfen ja eher Binarygröße für Speed einzutauschen durch Loopunrolling und Inlining. Naja, da muss man wohl mal ein wenig rumtesten, was man damit rausholen kann.



  • ich seh trotzdem nicht, was compileroptionen wie loop unrolling und sprachmerkmale wie "inline" mit c++ templates zu tun haben sollen...

    die stringklasse war sehr lehrreich. ich werd sie mir auch mal zerlegen und untersuchen.



  • c.rackwitz schrieb:

    ich seh trotzdem nicht, was compileroptionen wie loop unrolling und sprachmerkmale wie "inline" mit c++ templates zu tun haben sollen...

    loop-Unrolling kannst du über ein entsprechendes Template-Metaprogramme z.B. erzwingen.
    Die inline-Expansion einer Funktion kann z.B. dank eines Templates überhaupt erst möglich werden. Beispiel: qsort vs. std::sort.





  • hier ein kleines Beispiel:

    #include <iostream>
    
    using namespace std;
    
    template<unsigned int N>
    inline void schreibNMal(const char s[])
    {	
    	schreibNMal<N-1>(s);
    	cout<<N<<": "<<s;
    }
    
    template<>
    inline void schreibNMal<1>(const char s[])
    {
    	cout<<"1: "<<s;
    }
    
    int main()
    {
    	schreibNMal<5>("unroll ohne compiler optionen\n");
    	cin.get();
    }
    


  • Das lohnt sich wohl nur bei so kleinen Loops, dass man es gleich selbst n-fach schreiben
    kann 😉 Aber okay, es sieht cooler aus 🤡



  • @Bunny
    eine klasse ist fehlerhaft!



  • Hi,

    hier ein kleines C++-Beispiel:

    #include <iostream>
    #include <string>
    #include <sstream>
    
    int main(int argc, char* argv[])
    {
      try
      {
        double sum = 0;
        for (int a = 1; a < argc; ++a)
        {
          double w;
          std::istringstream in(argv[a]);
          if (in >> w)
            sum += w;
        }
        std::cout << "Die Summe ist " << sum << std::endl;
      }
      catch (const std::exception& e)
      {
        std::cerr << e.what() << std::endl;
      }
    }
    

    Unter SuSE-Linux 9.3 x86-64 mit "g++ -o ttt -O2 ttt.cpp" compliziert und mit "strip ttt" noch die Debug-infos raus. Das Ergebnis sind 19760 Bytes. Das ist noch weit weg vom 64k-Limit. Und das Trotz std::string, std::iostream, std::istringstream, exception-handling. Und das sogar auf einer 64-Bit-Plattform. Kein Grund für eine eigene String-Klasse.

    Solltet Ihr auf ein wesentlich anderes Ergebnis kommen, dann solltet Ihr vielleicht den Compiler wechseln. Alte Compiler hatten da so ihre Probleme.

    Templates sind praktisch Makros. Alles was nicht verwendet wird, wird auch nicht implementiert. Eine Template-Klasse darf jede Menge Zeugs mit bringen. Wenn es nicht verwendet wird, taucht es im binary nicht auf. Das geht sogar so weit, daß nicht verwendeter Template-code gewisse Fehler enthalten darf, wie z. B. Aufruf von nicht vorhandenen Methoden.



  • @tntnet! Hab es mal ausprobiert unter...

    VC++2003 Standard Edition: 112 KByte ohne Optimierung
    VC++2005 Beta 2 Express Edition: 7,5 KB ohne Optimierung



  • Artchi schrieb:

    @tntnet! Hab es mal ausprobiert unter...

    VC++2003 Standard Edition: 112 KByte ohne Optimierung
    VC++2005 Beta 2 Express Edition: 7,5 KB ohne Optimierung

    😮 😮 😮 😮 😮 😮 😮 👎 😮



  • @tntnet
    vorallem hast du den Code nicht auf Größe optimiert (-Os anstelle -O2)

    ich hab mit dem GCC 3.4 und folgenden Flags
    g++ -Wall -W -std=c++98 -Os -s -march=athlon-xp -mtune=athlon-xp -mfpmath=sse c++size.cpp
    ein 6,2K großes Binary erzeugt. Wobei man bei 64k demos wohl auch statisch linken muss, was wieder ein schlechtes Licht auf die STL wirft. Benutz mal das -static flag und zack ist das Binary 942K groß!



  • VC++ 2003: Release-Version, 104 kb (ohne Anpassung irgenwelcher Optionen)



  • Es kommt darauf an ob man die Laufzeitbibliothek statisch oder dynamisch dazu linkt. Dynamisch ist die Exe nur noch 5,5 KB groß, brauch dann aber ne DLL.



  • das heißt also das die templates nicht an der codegröße schuld sind.


Anmelden zum Antworten