C++ ungeeignet für 64K Demos?



  • volkard schrieb:

    weil bei windows ein kleines speichermanagement eingebaut ist. es ist langsam und so, kein vergleich zum mitgelieferten operator new. aber es ist extrem wenig code für's eigene programm.

    Das mitgelieferte new ruft über Umwege schon HeapAlloc auf.

    volkard schrieb:

    statische arrays sind noch billiger. zum freigeben braucht man gar keinen code und zum anlegen muß nur der stackpointer inkrementiert werden. außerdem werden statische arrays viel schneller angelegt.

    Statische Arrays beeinflussen den Stackpointer nicht. Das Anlegen geschieht, bevor main aufgerufen wird



  • vollkard schrieb:

    Das mitgelieferte new ruft über Umwege schon HeapAlloc auf.

    oder besser VirtualAlloc. mir geht es darum, die umwege wegzumachen. die umwege sind zum beispiel ein small object allocator, den man in c++ sinnvollerweise davorsetzt, um mehr speed zu bekommen. siehe modern c++ design. in der 64k-demo spare ich mir einfach den ganzen speed-bringenden umweg und mache ein lahmes, aber kleines new.

    vollkard schrieb:

    Statische Arrays beeinflussen den Stackpointer nicht. Das Anlegen geschieht, bevor main aufgerufen wird

    "statisch" hat mehr als eine bedeutung, scheint mir. ich meinte hier nur statisch im gegensatz zu dynamisch. mit dynamisch bezeichnet man speicher, den man sich zur laufzeit über aufrufe von new, malloc und so holt und dessen größe duchaus erst zur laufzeit bekannt sein kann. mit statisch bezeichnet man speicher, der per definition da ist, dessen größe erst zur compilezeit bekannt ist.
    in diesem sinne ist ein lokales array durchaus statisch.

    du scheinst das schlüsselwort static zu meinen. also im prinzip globalen variablen. der ist in der tat noch billiger, was die code-größe angeht.



  • @TGGC_work
    ich erteile dir hiermit virtuelles hausverbot für diesen thread. du darfst hier nicht mehr posten.
    ich logge, wie oft ich postings von dir lösche und behalte mir vor, dich bei zuwiderhandlung kostenpflichtig abzumahnen.



  • volkard schrieb:

    @TGGC_work
    ich erteile dir hiermit virtuelles hausverbot für diesen thread. du darfst hier nicht mehr posten.
    ich logge, wie oft ich postings von dir lösche und behalte mir vor, dich bei zuwiderhandlung kostenpflichtig abzumahnen.

    Gilt das für alle TGGC's?

    Bye, TGGC (Wähle deine Helden)



  • TGGC´ schrieb:

    Gilt das für alle TGGC's?

    Es gilt für alle, die, obwohl ich ein Posting gelöscht habe, es wieder einstellen. Im Falle dieses Störers dürften es an die 100 Löschungen schon sein. Und natürliche bedarf es keiner Warnung, bevor ich rechliche Schritte einleite, aber ich hoffe, er hört auf, ohne daß ich ganz fies werden muß.



  • 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.


Anmelden zum Antworten