Forum: Compiler & IDEs avr-g++ kennt new-Operator nicht


von Noop (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche gerade ein kleines Programm in c++ für den AVR zu testen. 
Leider kennt der g++-Compiler den new-Operator nicht. Wieso ist das so?

von Noop (Gast)


Lesenswert?

achso, die Fehlermeldung lautet:

" undefined reference to `operator new(unsigned int)'

von Timmo H. (masterfx)


Lesenswert?

vermutlich weil die Dateiendung ".c" und nicht ".cpp" ist. Ansonsten dem 
Compiler via " -x c++ " mitteilen dass es sich um C++ handelt.

von Karl H. (kbuchegg)


Lesenswert?

Ich schätze mal, da wird sich in der Zwischenzeit nicht viel verändert 
haben

Beitrag "c++ new und delete"

von Karl H. (kbuchegg)


Lesenswert?

Noop schrieb:
> achso, die Fehlermeldung lautet:
>
> " undefined reference to `operator new(unsigned int)'

"undefined reference" ist eine Fehlermeldung vom Linker, der aus dem 
bereits compilierten Einzelteilen dann das komplette Programm 
zusammenbaut.

von Noop (Gast)


Lesenswert?

Timmo H. schrieb:
> vermutlich weil die Dateiendung ".c" und nicht ".cpp" ist. Ansonsten dem
> Compiler via " -x c++ " mitteilen dass es sich um C++ handelt.

Danke für die Antwort. Leider hat beides nicht geholfen.

von Markus M. (mark_m)


Lesenswert?

Du erzeugst ein Objekt. Deshalb die Klammern nicht vergessen!
1
b = new CRectangle();

Grüsse

von Karl H. (kbuchegg)


Lesenswert?

Markus M. schrieb:
> Du erzeugst ein Objekt. Deshalb die Klammern nicht vergessen!

Nö.
Es gibt zwar einen klitzekleinen subtilen Unterschied ob mit Klammern 
oder ohne, aber die meisten C++ Programmierer werden da nie drüber 
stolpern, wenn sie sich an ein paar Basisregeln halten.

von Noop (Gast)


Lesenswert?

Ich habe die Klammer hinzugefügt. Dennoch will er nicht. Der MinGW 
compiliert dieses Beispiel problemlos durch. Vielleicht kann der AVR-g++ 
nicht alle Mechanismen von c++?

von Timmo H. (masterfx)


Lesenswert?

Noop schrieb:
>  Vielleicht kann der AVR-g++
> nicht alle Mechanismen von c++?
Korrekt, "richtiges" C++ macht auf einem µC auch nicht wirklich sinn 
(wenig RAM). Darum sind nur die wichtigsten Dinge implementiert. 
Ansonsten die Implementierung von Karl Heinz Buchegger verlinkten Thread 
verwenden

von Noop (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Beitrag "c++ new und delete"

Ok. Habe erst jetzt Deinen Beitrag gesehen. Ich lese mir das durch.

von Noop (Gast)


Lesenswert?

Timmo H. schrieb:
> Korrekt, "richtiges" C++ macht auf einem µC auch nicht wirklich sinn
> (wenig RAM).

Ja, da gibt es kontroverse Ansichten. Zu dieser Diskussion wollte ich 
gar nicht. Ich habe einfach nur lust das mal auszuprobieren.

von Markus M. (mark_m)


Lesenswert?

Dann musst Du noch die "stdc++" Library dazu linken.

g++ -o <program> <program>.cpp -lstdc++

Grüsse

von Noop (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Beitrag "c++ new und delete"

Ok. Der Thread hat geholfen. Mit dem Patch funktioniert es nun. 
Allerdings sind mehrdimensionale Geschichten wie :

CRectangle * d = new CRectangle[2];

nicht möglich. Das macht er dann nicht mit.

Markus M. schrieb:
> g++ -o <program> <program>.cpp -lstdc++

zeigt keine Änderung.

Aber vielen Dank.

von Markus M. (mark_m)


Lesenswert?

> CRectangle * d = new CRectangle[2];

> nicht möglich. Das macht er dann nicht mit.

Natürlich kann das nicht funktionieren, wenn es überhaupt keine "new" 
Implementierung gibt.

Du müsstest nun ebenso ein "new[]" und "delete[]" für Arrays 
implementieren. Schema wie oben.

http://en.cppreference.com/w/cpp/memory/new/operator_new

Grüsse

von Noop (Gast)


Lesenswert?

Markus M. schrieb:
> Natürlich kann das nicht funktionieren, wenn es überhaupt keine "new"
> Implementierung gibt.

Jo! Danke!

ich habe mal die New-Implentierung überladen und schon geht es auch mit 
Arrays:

void * operator new(size_t size)
{
  return malloc(size);
}

void* operator new[](size_t count/*, placement_params*/)
{
  return malloc(count);
}



Besten Dank von einem Noop!

von Markus M. (mark_m)


Lesenswert?

Und wie viel Speicher reserviert dir deine "new[]" Implementierung?

Ganz sich nicht "count*sizeof(CRectangle)" ;-)

Grüsse

von Noop (Gast)


Lesenswert?

Markus M. schrieb:
> Ganz sich nicht "count*sizeof(CRectangle)" ;-)

Ok. Darüber habe ich auch vorhin nachgedacht. Meinst Du es wird die 
Länge des ersten Array-Elements reserviert? Hast Du einen Tip?

von Markus M. (mark_m)


Lesenswert?

Ich hab mich gerade mal ein bisschen dahingehend schlau gemachte,  wenn 
"new" und "delete" nicht vorgesehen sind.

Normalerweise kümmert sich der Compiler darum, dass eine Klasse über 
"new", "delete", "new[]" und “delete[]" verfügt. Da der Compiler hier 
nicht tätig wird, müsstest Du für jede deiner Klassen diese Operatoren 
selbst implementieren.

Am besten Du vergisst "new", wenn es der Compiler nicht unterstützt. Du 
kannst Objekt Arrays immer noch auf dem Stack ablegen.

Das im Beitrag "c++ new und delete" 
beschrieben "new" ist nicht wirklich ein Ersatz, da nur die Anzahl von 
Bytes berücksichtigt wird und Datentypen ignoriert werden.

Man kann sich bei den einfachen Datentypen mit "sizeof()" behelfen. Bei 
Klassen funktioniert  es aber nicht mehr.

Mikrocontroller sind eine Welt für sich. Ich persönlich vermeide 
Dynamische Daten auf einem MC. Bezieht jetzt sich auf AVR.

Grüsse

von Karl H. (kbuchegg)


Lesenswert?

Markus M. schrieb:
> Ich hab mich gerade mal ein bisschen dahingehend schlau gemachte,  wenn
> "new" und "delete" nicht vorgesehen sind.
>
> Normalerweise kümmert sich der Compiler darum, dass eine Klasse über
> "new", "delete", "new[]" und “delete[]" verfügt. Da der Compiler hier
> nicht tätig wird, müsstest Du für jede deiner Klassen diese Operatoren
> selbst implementieren.


Du verwechselst den Operator new mit dem new Operator.
Das sind 2 verschiedene Dinge.
So wie Noop das gemacht hat, passt das schon.

von Kopfschüttler (Gast)


Lesenswert?

Noop schrieb:
> Ich habe die Klammer hinzugefügt. Dennoch will er nicht. Der MinGW
> compiliert dieses Beispiel problemlos durch. Vielleicht kann der AVR-g++
> nicht alle Mechanismen von c++?

Das soll wohl ein Witz sein!
"new" ist ja schließlich vollkommen unwichtig oer was?

von Rolf M. (rmagnus)


Lesenswert?

Kopfschüttler schrieb:
> Noop schrieb:
>> Ich habe die Klammer hinzugefügt. Dennoch will er nicht. Der MinGW
>> compiliert dieses Beispiel problemlos durch. Vielleicht kann der AVR-g++
>> nicht alle Mechanismen von c++?
>
> Das soll wohl ein Witz sein!
> "new" ist ja schließlich vollkommen unwichtig oer was?

Nun, offensichtlich ist es niemandem wichtig genug, um sich die Mühe zu 
machen, einen Patch für g++ einzureichen, der das nachrüstet. Aber du 
kannst das gerne tun, wenn du möchtest.

von Ralf G. (ralg)


Lesenswert?

Kopfschüttler schrieb:
> Das soll wohl ein Witz sein!
> "new" ist ja schließlich vollkommen unwichtig oer was?

Ich glaube, dazu ist hier alles geschrieben worden:
Beitrag "Objektorientierung mit avr gcc"
(Ich hatte mich da mit reingehangen. Karl Heinz Buchegger und Rolf 
Magnus haben mir das Thema mit unendlicher Geduld nahegebracht.)

von Markus M. (mark_m)


Lesenswert?

Danke Ralf,

den Thread kannte ich noch nicht. Dort wird das Thema erschöpfend 
behandelt. Gute Arbeit.


@Karl Heinz Buchegger
> Du verwechselst den Operator new mit dem new Operator.
> Das sind 2 verschiedene Dinge.
Ja, da hab ich ein zu weit ausgeholt. Ich dachte für das bessere 
Verständnis kann ich es so schreiben. Technisch sind es zwei paar 
Schuhe.

> So wie Noop das gemacht hat, passt das schon.
Nein, passt nicht. Er gibt "malloc" und "free" nur andere Namen.

Grüsse

von Noop (Gast)


Lesenswert?

Hm... also die Überladung funktioniert aber auch mit dem MinGW. Ich habe 
es dort ausprobiert und es scheint zu funktionieren. Mir fehlt definitiv 
zu viel Basiswissen. Ich habe mal in der libsupc++ nachgesehen.

Die machen das so:
1
_GLIBCXX_WEAK_DEFINITION void *
2
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
3
{
4
  void *p;
5
6
  /* malloc (0) is unpredictable; avoid it.  */
7
  if (sz == 0)
8
    sz = 1;
9
  p = (void *) malloc (sz);
10
  while (p == 0)
11
    {
12
      new_handler handler = std::get_new_handler ();
13
      if (! handler)
14
  _GLIBCXX_THROW_OR_ABORT(bad_alloc());
15
      handler ();
16
      p = (void *) malloc (sz);
17
    }
18
19
  return p;
20
}

und für ein Array analog:
1
_GLIBCXX_WEAK_DEFINITION void*
2
operator new[] (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
3
{
4
  return ::operator new(sz);
5
}

So habe ich dann einfach mal das gemacht:
1
void * operator new(size_t size)
2
{
3
  return malloc(size);
4
}
5
6
void * operator new[](size_t size /*, placement_params*/)
7
{
8
  return operator new(size);
9
}

es scheint auch zu funktionieren. Da mir persönlich Wissen und Erfahrung 
mit C++ (und grundsätzlich auch in C) fehlt, versuche ich mir das so zu 
erklären:
(Achtung das kann jetzt ein Donnerwetter erzeugen, weil es vielleicht 
total falsch ist)


Der new-operator ist grundsätzlich ein Zeiger auf ein Objekt. Er ruft 
malloc auf und bekommt von malloc die Speicheradresse des reservierten 
Speicherplatzes zurück und ordnet diese dann dem ursprünglich zu 
deklarierenden Object zu:

 CRectangle * d = new CRectangle[200];

also hier *d. Mir ist nicht klar, woher der Compiler weiß, dass er das 
Argument (size_t size) die Länge/Größe des Objekts ist. Aber es 
erscheint mir logisch, dass wenn das funktioniert, es völlig egal ist, 
ob es ein Array oder ein einzelnes Element ist. Das Objekt hat ja immer 
eine Endmarkierung im Speicher. So auch ein Array. Naja, weiter reicht 
mein dummes Hirn nicht ...

von Karl H. (kbuchegg)


Lesenswert?

Markus M. schrieb:

>> So wie Noop das gemacht hat, passt das schon.
> Nein, passt nicht. Er gibt "malloc" und "free" nur andere Namen.

Und genau das reicht auch schon für den globalen new Operator im 
einfachsten Fall. Ok, ein bischen Fehlerbehandlung könnte man noch 
machen, aber mehr ist nicht notwendig.
Der Auftrag an den globalen Operator new lautet: besorge Speicher.
Mehr braucht er nicht tun. Den Rest erledigt der Aufrufer (wie zb die 
entsprechenden Objekte in diesem Speicher zu konstruieren)

von Karl H. (kbuchegg)


Lesenswert?

Noop schrieb:

> Der new-operator ist grundsätzlich ein Zeiger auf ein Objekt.

Der gloable operator new ist zualerst mal eine Funktion :-)

> Er ruft
> malloc auf und bekommt von malloc die Speicheradresse des reservierten
> Speicherplatzes zurück und ordnet diese dann dem ursprünglich zu
> deklarierenden Object zu:

Dieser globale operator new hat mit Objekten überhaupt nichts am Hut. 
Seine Aufgabe ist es Speicher zu besorgen. Nicht mehr und nicht weniger. 
Was dann mit diesem Speicher weiter passiert, hat ihn nicht zu 
interessieren.

>  CRectangle * d = new CRectangle[200];
>
> also hier *d.

d ist ein Pointer.

> Mir ist nicht klar, woher der Compiler weiß, dass er das
> Argument (size_t size) die Länge/Größe des Objekts ist.

Na der Compiler weiß doch, wie groß ein CRectangle Objekt ist. Du hast 
das ja vorher in Form der Klassen-Deklaration bekannt geben müssen. Der 
Compiler hat die analysiert und festgestellt, wieviel Speicher benötigt 
wird, um 1 Objekt davon zu erzeugen. Und diese Größe übergibt er an den 
globalen Operator new (oder wie in deinem letzten Beispiel das 200-fache 
davon), wenn er im Zuge der Objektkonstruktion erst mal den Speicher für 
dieses Objekt anlegen muss. Operator new besorgt den Speicher und der 
Compiler sorgt dann dafür, dass ein entsprechender Konstruktor für 
diesen Speicher aufgerufen wird (oder im Falle eines Arrays eine 
entsprechende Anzahl an Konstruktoren für jedes Objekt einzeln). Aber 
damit hat der globale Operator new schon nichts mehr zu tun. Für ihn 
endet die ganze Sache damit, dass er einen entsprechend großen 
Speicherbereich organisiert hat. Wie er das macht, dass ist diesem 
Operator überlassen. Zum Beispiel kann er das mit einem malloc machen. 
Er könnte aber genausogut auch selbst eine entsprechende 
Speicherverwaltung in einem vorallokierten Byte-Array machen, wenn das 
dem Programmierer lieber ist und er das so ausprogrammiert. Oder er 
könnte an malloc()/free() vorbei sich selbst mit dem Betriebssystem 
ausschnapsen, wie er an Speicher kommt.

Nicht zu verwechseln ist der Operator new mit dem new-Operator. Der 
globale Operator (wie hier) ist generell dafür zuständig Speicher zu 
besorgen. Der new-Operator als Klassenmember ermöglichst es einem 
Programmierer, für eine Klasse eine von der globalen 
Speicher-Allokier-Strategie abweichende Strategie auf Klassenbasis zu 
schaffen. Damit kann man zb kleine Objekte, die oft und häufig allokiert 
werden in einem Art Memory-Pool verwalten, ohne laufend durch die 
aufwändige dynamische Speicherverwaltung laufen zu müssen. Aber ... das 
ist eine andere Geschichte. Daru geht es hier nicht. Hier geht es darum, 
dass es irgendwo im C++ System mal eine unterste Ebene geben muss, die 
sich um Speicherallokierung und Freigabe kümmert. Genau auf dieser Ebene 
steigst du ein. Und in deinem Fall delegierst du das eben an die 
vorhandene Funktion malloc() bzw. free().

> Aber es
> erscheint mir logisch, dass wenn das funktioniert, es völlig egal ist,
> ob es ein Array oder ein einzelnes Element ist.

Im Prinzip: ja.
Allerdings hat man mit einem speziellen Operator für die Arrayform, dann 
als Systemprogrammierer die Möglichkeit, sich für diesen Fall etwas 
spezielles einfallen zu lassen. Ob man das dann auch benutzt oder nicht, 
ist eine andere Frage. Der Standardfall ist ganz einfach, dass der 
Array-Operator einfach den normalen Operator benutzt um seinen Auftrag 
zu erfüllen.

Hier ist einfach nur eine Möglichkeit für etwas 'Flexibilität' 
eingebaut. Ob man die dann nutzt und wofür man die nutzt, muss der 
Systemprogrammierer entscheiden.


> Das Objekt hat ja immer
> eine Endmarkierung im Speicher.

Ähm. Nein.

> So auch ein Array.

Nö. Wie sich die Speicherverwaltung merkt, wie groß der Speicher ist, 
auf den sie beim malloc einen Pointer rausgerückt hat, das ist das 
Problem der Speicherverwaltung. C++ kümmert sich da erst mal überhaupt 
nicht drumm. Der angeforderte Speicher muss die beim Aufruf angegebene 
Mindestgröße haben. Er kann auch größer sein, aber das Minimum wird beim 
Aufruf vorgegeben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.