 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Oliver Block Guest
|
Posted: Fri Feb 16, 2007 4:57 am Post subject: internals |
|
|
Hallo,
mich interessiert, wie eine Klasse, die in C++ definiert wurde, intern
repräsentiert wird? Ich weiß, daß C++ in C (und wahrscheinlich Assembler)
geschrieben wurde, was ich nicht weiß wie sie in C-Code aussieht.
Beispielklasse:
class MyClass
{
public:
void greeting();
void greeting(String name);
};
MyClass::MyClass()
{
}
void MyClass::greeting()
{
cout << "Hallo" << "\n";
}
void MyClass::greeting(String name)
{
cout << "Hallo " << name << "\n";
}
Ich hoffe das ist einigermaßen richtig.:)
Gruß,
Oliver |
|
| Back to top |
|
 |
Jens Müller Guest
|
Posted: Sat Feb 17, 2007 4:20 am Post subject: Re: internals |
|
|
Oliver Block schrieb:
| Quote: | Hallo,
mich interessiert, wie eine Klasse, die in C++ definiert wurde, intern
repräsentiert wird?
|
Wenn das da unten nicht wäre, hätte ich die Frage vernünftigerweise als
solche nach dem Speicherlayout von Objekten der Klasse verstanden. Bei
deiner Beispielklasse ist das einfach: Da die keine Attribute hat und
nicht virtuell ist, werden bei einem ordentlichen Compiler Objekte der
Klasse exakt 0 Bytes belegen.
| Quote: | Ich weiß, daß C++ in C (und wahrscheinlich Assembler)
geschrieben wurde,
|
Aha?
Was genau meinst Du damit, wenn Du sagst, daß "C++ in C geschrieben" wurde?
| Quote: | was ich nicht weiß wie sie in C-Code aussieht.
Beispielklasse:
class MyClass
{
public:
void greeting();
void greeting(String name);
};
MyClass::MyClass()
{
}
void MyClass::greeting()
{
cout << "Hallo" << "\n";
}
void MyClass::greeting(String name)
{
cout << "Hallo " << name << "\n";
}
Ich hoffe das ist einigermaßen richtig.
|
Was soll daran "in C-Code" aussehen? Das ist C++, warum sollte
irgendjemand daraus C machen? |
|
| Back to top |
|
 |
Michael Walter Guest
|
Posted: Sat Feb 17, 2007 4:46 pm Post subject: Re: internals |
|
|
Oliver Block schrieb:
| Quote: | mich interessiert, wie eine Klasse, die in C++ definiert wurde, intern
repräsentiert wird? Ich weiß, daß C++ in C (und wahrscheinlich Assembler)
geschrieben wurde, was ich nicht weiß wie sie in C-Code aussieht.
|
Zunächst mal solltest Du einen impliziten Konstruktur nicht explizit
definieren!
Na gut, dann mach ich mir mal den Spaß und übersetze den Fragment (!) in
C: Wenn man Dein Beispiel in C übersetzt, *könnte* (weil
Compiler-abhängig!) folgendes rauskommen:
struct MyClass
{};
void MyClass_greeting(struct MyClass* this)
{
std_operator_lsh_ostream_cstr(
std_operator_lsh_ostream_cstr(std_cout,"Hallo"),
"\n");
}
void MyClass_greetings(struct MyClass* this, struct std_String name)
{
std_operator_lsh_ostream_cstr(
std_operator_lsh_String(std_cout, name),
"\n");
} |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Sat Feb 17, 2007 5:29 pm Post subject: Re: internals |
|
|
Jens Müller wrote:
| Quote: | Oliver Block schrieb:
mich interessiert, wie eine Klasse, die in C++ definiert wurde, intern
repräsentiert wird?
Wenn das da unten nicht wäre, hätte ich die Frage vernünftigerweise als
solche nach dem Speicherlayout von Objekten der Klasse verstanden. Bei
deiner Beispielklasse ist das einfach: Da die keine Attribute hat und
nicht virtuell ist, werden bei einem ordentlichen Compiler Objekte der
Klasse exakt 0 Bytes belegen.
|
Mindestens ein Byte muss der Compiler schon dafür reservieren, damit du
verschiedene Instanzen der Klasse anhand ihrer this-Pointer auseinander-
halten kannst. Bei der Verwendung als Basisklasse darf dieses eine Byte
dann wieder wegoptimiert werden.
In C sind Strukturen ohne Member ansonsten gar nicht erst zulässig.
| Quote: | Was soll daran "in C-Code" aussehen? Das ist C++, warum sollte
irgendjemand daraus C machen?
|
Naja, "man" könnte der Comeau-C++-Compiler sein und versuchen, das
Programm zu übersetzen :)
Stefan |
|
| Back to top |
|
 |
Thomas Thiele Guest
|
Posted: Thu Feb 22, 2007 4:59 am Post subject: Re: internals |
|
|
Stefan Reuther schrieb:
| Quote: | Mindestens ein Byte muss der Compiler schon dafür reservieren, damit du
verschiedene Instanzen der Klasse anhand ihrer this-Pointer auseinander-
halten kannst. Bei der Verwendung als Basisklasse darf dieses eine Byte
dann wieder wegoptimiert werden.
|
Warum nicht auch bei Verwendung der Klasse?
Ich hätte angenommen bei einer Klasse
class A{
public:
int calcSum(int a, int b);
};
int A::calcSum(int a, int b) { return a + b; }
Und folgendem Code:
....
A a;
summe = a.calcSum(2,3);
A b;
summe += b.calcSum(4,6);
Wieso sollte da je ein Byte für a und b reserviert werden?
Ich hätte angenommen, dass im Assemblercode die Funktion behandelt
wird, wie eine globale "C-Funktion".
Was passiert bei: A* aa = new A[42]; ?
Wird da tatsächlich ein Array angelegt auch wenn ich nur Code der
folgenden Art schreibe.
for (int i = 0; i < 42; i++){
summe += aa[i].calcSum(i, i);
} |
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Thu Feb 22, 2007 11:46 pm Post subject: Re: internals |
|
|
Thomas Thiele wrote:
| Quote: | Stefan Reuther schrieb:
Mindestens ein Byte muss der Compiler schon dafür reservieren, damit du
verschiedene Instanzen der Klasse anhand ihrer this-Pointer auseinander-
halten kannst. Bei der Verwendung als Basisklasse darf dieses eine Byte
dann wieder wegoptimiert werden.
Warum nicht auch bei Verwendung der Klasse?
|
Weil jedes Objekt eine Adresse im Speicher hat. Wenn es keinen Speicher
belegt, gibt's aber auch keine Adresse.
Man könnte natürlich einfach irgendeine unbenutzte Adresse verwenden, aber
das geht spätestens bei Arrays nicht mehr.
| Quote: | Ich hätte angenommen bei einer Klasse
class A{
public:
int calcSum(int a, int b);
};
int A::calcSum(int a, int b) { return a + b; }
Und folgendem Code:
...
A a;
summe = a.calcSum(2,3);
A b;
summe += b.calcSum(4,6);
Wieso sollte da je ein Byte für a und b reserviert werden?
|
Wieso sollte man überhaupt so eine Klasse machen?
| Quote: | Ich hätte angenommen, dass im Assemblercode die Funktion behandelt
wird, wie eine globale "C-Funktion".
|
Dazu gibt's für Memberfunktionen 'static'. Dann brauchst du kein Objekt der
Klasse anzulegen, um sie zu benutzen.
| Quote: | Was passiert bei: A* aa = new A[42]; ?
Wird da tatsächlich ein Array angelegt auch wenn ich nur Code der
folgenden Art schreibe.
for (int i = 0; i < 42; i++){
summe += aa[i].calcSum(i, i);
}
|
Ja, aber wozu sollte solch ein Array gut sein? |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Thu Feb 22, 2007 11:54 pm Post subject: Re: internals |
|
|
Thomas Thiele wrote:
| Quote: | Stefan Reuther schrieb:
Mindestens ein Byte muss der Compiler schon dafür reservieren, damit du
verschiedene Instanzen der Klasse anhand ihrer this-Pointer auseinander-
halten kannst. Bei der Verwendung als Basisklasse darf dieses eine Byte
dann wieder wegoptimiert werden.
Warum nicht auch bei Verwendung der Klasse?
[leere Klasse A]
A a;
summe = a.calcSum(2,3);
A b;
summe += b.calcSum(4,6);
Wieso sollte da je ein Byte für a und b reserviert werden?
|
Es gibt immer noch die 'as-if' Regel. Der Compiler muss so tun, als
würde er hier ein Byte für a und eins für b reservieren. Wenn du aber
nicht nachkuckst, ob er das auch wirklich tut, kann er es auch bleiben
lassen.
In deinem Codebeispiel bestehen gute Chancen, dass der Compiler die
Unnötigkeit der Klasseninstanz erkennt.
| Quote: | Ich hätte angenommen, dass im Assemblercode die Funktion behandelt
wird, wie eine globale "C-Funktion".
|
Die bekommt aber drei Parameter, der erste davon ist der this-Pointer.
Der Compiler muss die Funktion 'calcSum' sehen, und erkennen, dass diese
den this-Pointer nicht benutzt. Dann darf er den this-Pointer
wegoptimieren und im nächsten Schritt feststellen, dass er für 'a'
keinen Speicher reservieren muss, weil keiner darauf zugreift. Wenn er
die Implementation von 'calcSum' nicht sieht, muss er davon ausgehen,
dass sie möglicherweise sowas wie 'std::cout << this' macht, und den
Speicher reservieren.
Das ändert ansonsten nichts daran, dass 'sizeof(A)' mindestens 1 ist.
| Quote: | Was passiert bei: A* aa = new A[42]; ?
Wird da tatsächlich ein Array angelegt auch wenn ich nur Code der
folgenden Art schreibe.
for (int i = 0; i < 42; i++){
summe += aa[i].calcSum(i, i);
}
|
Auch hier gilt wieder: ein unendlich kluger Compiler darf das
wegoptimieren, wenn dein Programm den Unterschied nicht feststellen
kann. Die Chancen, dass er es konkret bei diesem Code tut, gehen aber
gegen Null, da hier zu viele Unbekannte drin sind. Zum Beispiel könnte
ein anderes Modul den 'operator new[]' programmweit überschreiben, und
da definiert ist, dass 'new A[42]' jenen Operator mit einer Anforderung
über mindestens 42 Bytes aufruft, sollte der Compiler das auch tun.
Stefan |
|
| Back to top |
|
 |
Thomas Thiele Guest
|
Posted: Fri Feb 23, 2007 3:56 pm Post subject: Re: internals |
|
|
Rolf Magnus schrieb:
| Quote: | Weil jedes Objekt eine Adresse im Speicher hat. Wenn es keinen Speicher
belegt, gibt's aber auch keine Adresse.
|
Das ist doch aber genau der Punkt.
Wenn es nicht benötigt wird, wird es dann auch Instanziert inklusive
reserviertem Speicher?
| Quote: | Man könnte natürlich einfach irgendeine unbenutzte Adresse verwenden, aber
das geht spätestens bei Arrays nicht mehr.
|
Drum hatte ich das Beispiel auch gepostet.
Das Array wird durchlaufen und die Intanz der Klasse wird nirgend
benötigt.
| Quote: | Wieso sollte man überhaupt so eine Klasse machen?
|
Aus rein akademischen Interesse...;-)
| Quote: | Dazu gibt's für Memberfunktionen 'static'. Dann brauchst du kein Objekt der
Klasse anzulegen, um sie zu benutzen.
|
Schon richtig. Aber rein theoretisch gilt das auch für Funktionen die
ich static machen _könnte_.
Die Frage ist, erkennt das der Compiler oder "will" er unbedingt den
nichtbenötigeten this-Pointer auf den Stack legen und dazu die Klasse
instanzieren?
Ich beziehe mich mal auf gängige Compiler wie gcc, vc++, nicht auf
theoretische mögliche.
| Quote: | Ja, aber wozu sollte solch ein Array gut sein?
|
Aus rein akademischen Interesse... |
|
| Back to top |
|
 |
Thomas Thiele Guest
|
Posted: Fri Feb 23, 2007 3:59 pm Post subject: Re: internals |
|
|
Stefan Reuther schrieb:
| Quote: | Es gibt immer noch die 'as-if' Regel. Der Compiler muss so tun, als
würde er hier ein Byte für a und eins für b reservieren. Wenn du aber
nicht nachkuckst, ob er das auch wirklich tut, kann er es auch bleiben
lassen.
Auch hier gilt wieder: ein unendlich kluger Compiler darf das
wegoptimieren, wenn dein Programm den Unterschied nicht feststellen
kann.
|
Das war mein Gedanke. Die Frage ist: tun das reale Compiler? |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Fri Feb 23, 2007 11:19 pm Post subject: Re: internals |
|
|
Thomas Thiele wrote:
| Quote: | Stefan Reuther schrieb:
Auch hier gilt wieder: ein unendlich kluger Compiler darf das
wegoptimieren, wenn dein Programm den Unterschied nicht feststellen
kann.
Das war mein Gedanke. Die Frage ist: tun das reale Compiler?
|
Das glaubte ich mit dem Satz, den du weggeschnitten hast, ausgedrückt zu
haben: die Chancen, dass ein Compiler es bei der 'new'-Konstruktion tut,
gehen gegen Null. Mir ist kein Compiler bekannt, der das tut.
Für dein erstes Beispiel, etwas in Form gebracht,
class A {
public:
int calcSum(int a, int b);
};
int A::calcSum(int a, int b) { return a + b; }
int foo() {
int summe;
A a;
summe = a.calcSum(2,3);
A b;
summe += b.calcSum(4,6);
return summe;
}
generiert g++-3.4.4 (cygming-special) mit "-O3" den Code
__Z3foov:
pushl %ebp
movl $15, %eax
movl %esp, %ebp
popl %ebp
er optimiert die Variablen also weg. Borland C++ 5.5.1 tut das nicht,
und ruft brav die Funktion mit drei Parametern auf. Den new-Aufruf
optimieren sie nicht weg.
Stefan |
|
| Back to top |
|
 |
Georg Maaß Guest
|
Posted: Sat Feb 24, 2007 9:09 pm Post subject: Re: internals |
|
|
Stefan Reuther wrote:
| Quote: | Auch hier gilt wieder: ein unendlich kluger Compiler darf das
wegoptimieren, wenn dein Programm den Unterschied nicht feststellen
kann.
|
Wenn wir schon beim Wegoptimieren sind, wenn ein unendlich kluger
Compiler feststellt, das ein Programm, egal was passiert, immer den
selben Rückgabewert (z.B. 1) liefert, darf er es dann auf folgende
optimierte Fassung eindampfen?
int main(int argc, char **argv)
{
return 1;
}
Wenn der Rückgabewert immer gleich ist, von nichts abhängt, dann kann
man doch den ganzen Kram, der den Rückgabewert nicht beeinflußt,
wegoptimieren und das Programm auf diesen Ressourcen schonenden Rumpf
eindampfen.
Wenn man dann auch noch dem Kompilat den dateinamen "return 1" gibt,
dann ist es auch dem Endanwender offensichtich, was das Programm macht,
so daß er sich das laufen lassen sparen kann, weil er ja das Ergebnis
schon kennt.  |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Sun Feb 25, 2007 6:53 pm Post subject: Re: internals |
|
|
On Feb 24, 4:09 pm, Georg Maaß <g...@bioshop.de> wrote:
| Quote: | Stefan Reuther wrote:
Auch hier gilt wieder: ein unendlich kluger Compiler darf das
wegoptimieren, wenn dein Programm den Unterschied nicht feststellen
kann.
Wenn wir schon beim Wegoptimieren sind, wenn ein unendlich kluger
Compiler feststellt, das ein Programm, egal was passiert, immer den
selben Rückgabewert (z.B. 1) liefert, darf er es dann auf folgende
optimierte Fassung eindampfen?
int main(int argc, char **argv)
{
return 1;
}
|
Wenn es kein anderes von außen sichtbares Verhalten (IO oder
Zugriffe auf volatilen Objekten) hat. In der Vergangenheit
haben auch einige Benchmarks damit Probleme gehabt.
| Quote: | Wenn der Rückgabewert immer gleich ist, von nichts abhängt, dann kann
man doch den ganzen Kram, der den Rückgabewert nicht beeinflußt,
wegoptimieren und das Programm auf diesen Ressourcen schonenden Rumpf
eindampfen.
Wenn man dann auch noch dem Kompilat den dateinamen "return 1" gibt,
dann ist es auch dem Endanwender offensichtich, was das Programm macht,
so daß er sich das laufen lassen sparen kann, weil er ja das Ergebnis
schon kennt.
|
Die Norm spricht von sichtbarem Verhalten. Wenn Code kein
Einfluß auf einer Ausgabe bzw. einem Zugriff auf ein volatiles
Objekt hat, und das Ergebnis auch nicht beeinflußt, darf er
freilich wegoptimisiert werden. Und auch heutigen Compiler
tun's, mindestens in den einfachsten Fällen und auch zum Teil in
komplizierteren Fällen.
--
James Kanze (Gabi Software) email: james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Sun Feb 25, 2007 6:55 pm Post subject: Re: internals |
|
|
Georg Maaß wrote:
| Quote: | Stefan Reuther wrote:
Auch hier gilt wieder: ein unendlich kluger Compiler darf das
wegoptimieren, wenn dein Programm den Unterschied nicht feststellen
kann.
Wenn wir schon beim Wegoptimieren sind, wenn ein unendlich kluger
Compiler feststellt, das ein Programm, egal was passiert, immer den
selben Rückgabewert (z.B. 1) liefert, darf er es dann auf folgende
optimierte Fassung eindampfen?
|
Sofern es außer dem Rückgabewert keinerlei Ausgaben produziert, ja. Das ist
aber nur bei wenigen Programmen der Fall.
| Quote: | int main(int argc, char **argv)
{
return 1;
}
Wenn der Rückgabewert immer gleich ist, von nichts abhängt, dann kann
man doch den ganzen Kram, der den Rückgabewert nicht beeinflußt,
wegoptimieren und das Programm auf diesen Ressourcen schonenden Rumpf
eindampfen.
Wenn man dann auch noch dem Kompilat den dateinamen "return 1" gibt,
dann ist es auch dem Endanwender offensichtich, was das Programm macht,
so daß er sich das laufen lassen sparen kann, weil er ja das Ergebnis
schon kennt.
|
Es gibt solche Programme trotzdem. Auf meinem System gibt es /bin/true
und /bin/false, die genau sowas machen. Die werden aber normalerweise nicht
vom Anwender selbst gestartet, sondern in Shellskripten verwendet. |
|
| Back to top |
|
 |
Georg Maaß Guest
|
Posted: Sun Feb 25, 2007 7:18 pm Post subject: Re: internals |
|
|
James Kanze wrote:
| Quote: | Die Norm spricht von sichtbarem Verhalten.
|
Was ist sichtbares Verhalten?
Wenn ich eine Routine aus einer Fremdbibliothek (z.B. Betriebssystem)
aufrufe, von der der Compiler nur die Header-Datei sieht, wie soll er
wissen, ob in dieser Black-Box irgend was relevantes passieren kann. Ich
habe ja kein Schlüsselwort, mit dem ich im Header kennzeichnen könnte,
daß eine Funktion beispielsweise einen relevanten Seiteneffekt (z.B.
Ausgabe von irgendwas, Fenster öffnen, etc.) hat.
| Quote: | Wenn Code kein
Einfluß auf einer Ausgabe bzw. einem Zugriff auf ein volatiles
Objekt hat, und das Ergebnis auch nicht beeinflußt, darf er
freilich wegoptimisiert werden. Und auch heutigen Compiler
tun's, mindestens in den einfachsten Fällen und auch zum Teil in
komplizierteren Fällen.
|
Meinst Du damit die Template-Magie, bei welcher Aufrufe von leeren
Funktionsrumpfen genutzt werden, die man theoretisch weglassen könnte,
und von denen der Programmierer hofft, daß der Compiler sie tatsächlich
wegläßt. (Debug-Templates, die bei anderer Konfiguration tatsächlich
nicht leere Funktionen implementieren). |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Sun Feb 25, 2007 11:11 pm Post subject: Re: internals |
|
|
Georg Maaß wrote:
| Quote: | James Kanze wrote:
Die Norm spricht von sichtbarem Verhalten.
Was ist sichtbares Verhalten?
|
Das schrieb James bereits: Ausgaben und Zugriffe auf volatile-Objekte.
Oder auf standardesisch: "The observable behavior of the abstract
machine is its sequence of reads and writes to volatile data and calls
to library I/O functions." (1.9p6).
| Quote: | Wenn ich eine Routine aus einer Fremdbibliothek (z.B. Betriebssystem)
aufrufe, von der der Compiler nur die Header-Datei sieht, wie soll er
wissen, ob in dieser Black-Box irgend was relevantes passieren kann. Ich
habe ja kein Schlüsselwort, mit dem ich im Header kennzeichnen könnte,
daß eine Funktion beispielsweise einen relevanten Seiteneffekt (z.B.
Ausgabe von irgendwas, Fenster öffnen, etc.) hat.
|
Ganz einfach: Wenn der Compiler das nicht weiß, kann er die Optimierung
nicht durchführen.
| Quote: | Und auch heutigen Compiler tun's, mindestens in den einfachsten
Fällen und auch zum Teil in komplizierteren Fällen.
Meinst Du damit die Template-Magie, bei welcher Aufrufe von leeren
Funktionsrumpfen genutzt werden, die man theoretisch weglassen könnte,
und von denen der Programmierer hofft, daß der Compiler sie tatsächlich
wegläßt.
|
Das Wegoptimieren von leeren inline-Funktionen würde ich als Stand der
Technik bezeichnen. Das ist das Minimum, was ich von einem Compiler erwarte.
Stefan |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|