C++ zukunftssicher?
-
groovemaster schrieb:
Jetzt könnte man meinen, dass damit keine Plattformunabhängigkeit gewährleistet ist, was für die Binaries sicherlich auch stimmt. Der Code selbst kann jedoch trotzdem plattformunabhängig sein. Insofern trifft der Spruch "Write Once, Run Anywhere" auch auf C++ zu. Du musst halt nur für die unterschiedlichen Plattformen neu übersetzen.
Das sehe ich anders. In C++ hast du keine Garantien über die Größe und das Layout von Datentypen, oder die Implementierung der STL.
Beispiel 1: Prozessor A rechnet -1 / 10 == -1, Prozessor B rechnet -1 / 10 == 0
Gibt es beides. Und was rauskommt ist so toll "implementation defined"Beispiel 2: Prozessor A macht 1er Komplement (ein gammeliges Handy halt), Prozessor B macht 2er Komplement.
Beispiel 2: Ich kann Programm mit andern Compiler nicht übersetzen weil bei Compiler x <iostream> <string> mit inkludiert, beim andern nicht
... [endlose Liste fortsetzen] ...
In C++, habe ich das Gefühl, versteht man unter Plattformunabhängigkeit eher den Fakt, dass man auch für nen Toaster einen Compiler schreiben kann. Aber der geschriebene C++ Code, kann sich auf verschiedenen Plattformen/mit verschiedenen Compilern völlig anders verhalten. Daher vermute ich, scheint man in C++ unter "Plattformunabhängigkeit" nicht "Write Once, Run Anywhere", sondern "get a compiler everywhere" zu verstehen. Das deckt sich auch mit dem Design der stdlib. Es gibt nichts (z.B. filesystem), was auf nen Toaster nicht vorhanden sein könnte. Aber genau das erschwert es schon wieder, portablen Code zu schreiben.
-
Optimizer schrieb:
Das sehe ich anders. In C++ hast du keine Garantien über die Größe und das Layout von Datentypen
Was jedoch vollokmmen irrelevant ist. ZB bedeutet int nunmal, du hast eine vorzeichenbehaftete Ganzzahl. Punkt. Nicht mehr und nicht weniger. Und wenn du genaue Bitgrössen brauchst, dann baust du dir dafür einen entsprechenden Typ. Vielleicht gibts ja auch irgendwann eine <cstdint> Headerdatei.
Optimizer schrieb:
oder die Implementierung der STL.
In bestimmten Punkten ist die STL sicherlich abhängig vom System. Das wirft das plattformunabhängige Konzept der STL aber noch lange nicht über den Haufen.
Optimizer schrieb:
Beispiel 1: Prozessor A rechnet -1 / 10 == -1, Prozessor B rechnet -1 / 10 == 0
Gibt es beides. Und was rauskommt ist so toll "implementation defined"Meines Wissens darf laut Standard hier niemals -1 rauskommen, sondern nur 0. IIRC muss bei Ganzzahldivision der "Nachkommaanteil" (bzw. Rest) abgeschnitten werden.
Da kann ich mich aber auch täuschen. Wenn hier auf einem System also -1 rauskommt, würde ich dieses als nicht vom Standard abgedeckt sehen. Insofern ist mir dort Plattformunabhängigkeit relativ egal.Optimizer schrieb:
Beispiel 2: Prozessor A macht 1er Komplement (ein gammeliges Handy halt), Prozessor B macht 2er Komplement.
Was ebenfalls vollkommen irrelevant ist. Die C++ Operatoren sind ja eindeutig definiert. Wie letztendlich das Layout der CPU aussieht interessiert nur den Compiler, aber nicht uns. Sicherlich gibt es gewisse Aussnahmen, wie zB das Shiften von negativen Werten, die implementationsspezifisch sind. Und darüber muss man sich halt im Klaren sein.
Optimizer schrieb:
Beispiel 2: Ich kann Programm mit andern Compiler nicht übersetzen weil bei Compiler x <iostream> <string> mit inkludiert, beim andern nicht
Ich habe zwar nicht den kompletten Standard im Kopf
, aber afaik sind für alle Klassen und Funktionen die Header spezifiziert. Insofern sehe ich keine Probleme damit. Wenn überhaupt, dann ist eine STL Implementierung fehlerhaft. Aber wer garantiert dir denn, dass die JVM auf einem bestimmten System vollkommen fehlerfrei funktioniert?Optimizer schrieb:
In C++, habe ich das Gefühl, versteht man unter Plattformunabhängigkeit eher den Fakt, dass man auch für nen Toaster einen Compiler schreiben kann. Aber der geschriebene C++ Code, kann sich auf verschiedenen Plattformen/mit verschiedenen Compilern völlig anders verhalten. Daher vermute ich, scheint man in C++ unter "Plattformunabhängigkeit" nicht "Write Once, Run Anywhere", sondern "get a compiler everywhere" zu verstehen.
Dann verstehst du in Java unter Plattformunabhängigkeit "get a vm everywhere"?

Tja, dann frag ich mich, was Java oder C# wohl auf einem Toaster machen würden.

Optimizer schrieb:
Das deckt sich auch mit dem Design der stdlib. Es gibt nichts (z.B. filesystem), was auf nen Toaster nicht vorhanden sein könnte. Aber genau das erschwert es schon wieder, portablen Code zu schreiben.
Klar, es ist immer die Frage, wie man Plattformunabhängigkeit definiert. Für mich ist es wie gesagt das "Write Once, Run Anywhere" Prinzip. Und das kann man auch mit C++ relativ gut handeln. Der Aufwand ist zwar teilweise höher, aber du hast dafür letztendlich viele Freiheiten. Und ob du für die diversen Plattformen unterschiedliche Compiler oder VMs bereitstellst, ist ja letztendlich gehüpft wie gesprungen. Und wenn du ein Programm, welches mit Dateien arbeitet, auf ein System portieren willst, was kein Dateisystem kennt, dann stellt sich für mich die Frage nach dem Sinn des Ganzen. Das ist so, wie wenn du jemandem ein Auto kaufen willst, der überhaupt keinen Führerschein hat.
-
groovemaster schrieb:
Wenn hier auf einem System also -1 rauskommt, würde ich dieses als nicht vom Standard abgedeckt sehen. Insofern ist mir dort Plattformunabhängigkeit relativ egal.
Höh? Weil es nicht abgedeckt ist, ist es egal? Es ist gerade nicht egal. Es geht hier genau um den Standard. Es ging um "write once, run anywhere". Wenn es hier Unterschiede gibt, ist es "write once, debug anywhere".
groovemaster schrieb:
Was ebenfalls vollkommen irrelevant ist. Die C++ Operatoren sind ja eindeutig definiert.
Ja sind sind eindeutig implementation-defined definiert.
Warum behauptest du, das sei irrelevant? Es ist äußerst unglaubwürdig, "write once, run anywhere" zu postulieren und dann zu behaupten dass Unterschiede in der Arithmetik irrelevant sind. Unterschiede in der Arithmetik verändern das Verhalten deines Programms und sind für die Semantik eines Programm höchst relevant. Du musst es umschreiben, damit es sich auf der neuen Plattform wie gewohnt verhält. Mit bedingter Compilierung kann man da natürlich schon was rausholen, aber das macht die Sache nicht weniger kompliziert.Ich habe zwar nicht den kompletten Standard im Kopf
, aber afaik sind für alle Klassen und Funktionen die Header spezifiziert.Darauf wollte ich nicht hinaus. Die Header können unterschiedlich implementiert sein, z.B. könnte die Implementierung von <string> den Header <cstring> inkludieren, bei einem anderen Compiler aber nicht. In einem Programm, wo ich jetzt <string> inkludiere, steht mir dann strcpy() vielleicht zur Verfügung, vielleicht auch nicht. Wenn der eine Compiler es mir zur Verfügung stellt, merke ich nicht, dass ich eigentlich <cstring> noch inkludieren müsste und kann mein Programm woanders nicht übersetzen. Das ist nichts, was man nicht schnell beheben kann, klar. Aber es macht sich nicht gut bei Abgaben
und zeigt, dass zwei völlig standardkonforme Implementierungen der STL einen Unterschied machen können.Dann verstehst du in Java unter Plattformunabhängigkeit "get a vm everywhere"?

Nein. Der höchst entscheidende Unterschied ist, Java-Code verhält sich bei jeder standardkonformen Java-Implementierung "gleich", bzw. liegen die Unterschiede in sehr viel kleineren Details. Wenn ich auf einem Handy ein long habe, ist es eine 64Bit-Zahl im 2er-Komplement mit exakt definierter Divisions- und Modulorechnung. Das heißt, ich nehme meinen Code für mein Handy wie er ist und lasse ihn auf einem anderen Handy laufen. Dass ich ihn nicht neu kompilieren muss, ist nicht der große Vorteil. Der Vorteil ist, dass der Source semantisch identisch ist.
Tja, dann frag ich mich, was Java oder C# wohl auf einem Toaster machen würden.

Da gibt es dann eine Java Toaster Edition, so wie es eine Micro Edition für Handy-Programmierung gibt.
Die unterscheiden sich im wesentlichen in der Standardbibliothek, da fallen dann Dinge wie Dateisystem raus.
Das wichtige ist aber, dass die Sprache selber keine Freiheiten lässt, was bestimmte Konstrukte bewirken. Diese Garantie hast du in vielen Sprachen, aber nicht in C oder C++, denn möglicherweise gibt es eine Waschmaschine, auf der das nicht effizient umzusetzen wäre.groovemaster schrieb:
Klar, es ist immer die Frage, wie man Plattformunabhängigkeit definiert. Für mich ist es wie gesagt das "Write Once, Run Anywhere" Prinzip.
Genau, für mich auch.
Und ob du für die diversen Plattformen unterschiedliche Compiler oder VMs bereitstellst, ist ja letztendlich gehüpft wie gesprungen.
Klar, aber darum geht es mir nicht. Es geht mir darum, dass geschriebener Source-Code die selbe Semantik hat. Dass Berechnungen immer das selbe rauskriegen, egal auf welchem System. Es ist mir egal, wenn das 2er Komplement emuliert wird und langsam ist, von einem "falschen" Ergebnis habe ich gar nichts. Wie gesagt, in anderen Sprachen hat das auch seine Grenzen. Das fängt bei Java aber erst damit an, dass die Auflösung von System.nanotime() unterschiedlich ist, bei C++ geht es schon bei grundlegenden Dingen wie Ganzzahl-Arithmetik los.
Klar büßen andere Sprachen dafür ein, weil man sie nicht nach überallhin portieren kann. Deshalb wählt der gute Informatiker für alles das geeignete Werkzeug und weiß, dass es nichts gibt, was immer das beste ist. C++ versucht aber, überall gut implementierbar und benutzbar zu sein und scheitert dabei.
Und wenn du ein Programm, welches mit Dateien arbeitet, auf ein System portieren willst, was kein Dateisystem kennt, dann stellt sich für mich die Frage nach dem Sinn des Ganzen. Das ist so, wie wenn du jemandem ein Auto kaufen willst, der überhaupt keinen Führerschein hat.
Das ist ein guter Punkt, den kann man kaum leugnen. Diesem Punkt versucht man beispielsweise mit Java Micro Edition oder .Net Compact Framework zu begegnen, um die möglichen Zielplattformen zumindest etwas auszudehnen. Aber wenn es keine Straßen gibt, macht ein Auto irgendwann auch keinen Sinn mehr. :xmas1: Da ist es dann besser, man nimmt für die Großstadt die U-Bahn, für das Land ein Auto und für die Pampa ein gutes Paar Schuhe, anstatt einen Schuh mit eingebauter U-Bahn zusammenzufrickeln, den man überall irgendwie benutzen kann.
-
seit wann trollt man jetzt nicht mehr mit anonymen nicks?

-
Optimizer schrieb:
Beispiel 1: Prozessor A rechnet -1 / 10 == -1, Prozessor B rechnet -1 / 10 == 0
prozessor A ist eindeutig kaputt
Optimizer schrieb:
Tja, dann frag ich mich, was Java oder C# wohl auf einem Toaster machen würden.

Da gibt es dann eine Java Toaster Edition, so wie es eine Micro Edition für Handy-Programmierung gibt.
der unterschied ist nur: ein mit c++ programmierter toaster kostet im handel unter 100 euro, einer mit java oder c# weit über 500€
-
*gähn*
Man kann in C++ so programmieren dass es auf mehreren Plattformen übersetzt werden kann, oftmals macht mans nicht weils einfacher ist.Ob C++ zukunftssicher ist... JA!
Unabhängig davon wie toll die Sprache ist oder ob es eine besser Programmiersprache gibt/geben wird sind hierfür zu viele Programme die in C++ geschrieben.
Damit C++ aussterben könnte müsste man erst mal die vorhandenen C++-Programme umschreiben, was ein paar Jahrzehnte dauern, die Weiterentwicklung auf genau die selbe Zeit blockiert und ein schweine Geld kosten dürfte (ohne einen erkennbaren Nutzen für den Anwender).
Da dies niemand der bei Verstand ist macht, wird uns C++ wie auch noch ältere Programmiersprachen eine ganze Weile erhalten bleiben und auch bei Neuentwicklungen eingesetzt werden.
-
Mathias schrieb:
*gähn*
Man kann in C++ so programmieren dass es Plattform übergreifend ist, oftmals machtDu kannst auch zu Fuß nach Moskau gehen.
-
Soll Leute geben, die das gemacht haben.

-
net schrieb:
Optimizer schrieb:
Beispiel 1: Prozessor A rechnet -1 / 10 == -1, Prozessor B rechnet -1 / 10 == 0
prozessor A ist eindeutig kaputt
Nein, der Rest ist 9. Nur weil du das nicht kennst, heißt das nicht, dass es das nicht gibt. So ein System hat Vorteile beim arithmetischen Shiften.
-
Optimizer schrieb:
net schrieb:
Optimizer schrieb:
Beispiel 1: Prozessor A rechnet -1 / 10 == -1, Prozessor B rechnet -1 / 10 == 0
prozessor A ist eindeutig kaputt
Nein, der Rest ist 9. Nur weil du das nicht kennst, heißt das nicht, dass es das nicht gibt. So ein System hat Vorteile beim arithmetischen Shiften.
das hat vorteile? welche? wo gibt es das? hast du ein beispiel?
-
Ich bin darüber gestolpert als ich mit dem MMIX-Assembler gearbeitet habe. Ich weiß jetzt aber nicht mehr, ob der Rest wirklich 9 war. Müsste ich drüber nachdenken, wie dieses System funktioniert.
Die Vorteile beim shiften aber liegen doch auf der Hand. Der arithmetische Rechtsshift von -1 ist billig:1111 / 2 = 1111
Einfach den Wert vom MSB nachschieben, bei positiven Zahlen ergibt sich das gewohnte Verhalten und bei negativen ist hier -1/2 == -1
-
huch? komisch. schlieslich ist eine division was anderes als ein bitshift (bis auf ein paar wenige ausnahmen). wie so'n prozessor intern seine bits verwaltet ist ja eigentlich egal, aber eine integerdivision muss doch 0 ergeben, wenn der teiler zu gross ist, oder nicht? davon abgesehn: wenn man sich fehler einhandelt beim shiften von negativen zahlen hat man natürlich selber schuld...
-
huch? komisch. schlieslich ist eine division was anderes als ein bitshift (bis auf ein paar wenige ausnahmen). wie so'n prozessor intern seine bits verwaltet ist ja eigentlich egal, aber eine integerdivision muss doch 0 ergeben, wenn der teiler zu gross ist, oder nicht?
Nein. Die Division ist dort so definiert, damit man einen arithmetischen Shift leichter bauen kann. Außerdem ist es mathematisch korrekter, weil der Rest immer positiv ist. Man muss das System nicht besser finden, aber es gibt es halt.
davon abgesehn: wenn man sich fehler einhandelt beim shiften von negativen zahlen hat man natürlich selber schuld...
Was soll denn das jetzt? Ich habe dir gezeigt, dass es Prozessoren gibt, die anders dividieren. Was hat das mit "selber schuld" zu tun?

-
also ich finde das seltsam. seit wann kann jeder selber definieren was bei einer division herauskommt?. na gut, dann bastel ich eben einen prozessor der bei division durch grosse zahlen 0x81 berechnet, weil's sich so schön digital verarbeiten lässt. ist ja albern sowas (daumen runter!)
btw: man kann nicht alle / durch bitshifts ersetzen. malnehmen aber geht.
-
Optimizer! Deine Ansicht ist wirklich merkwürdig und ich kann dir hier auch nicht zustimmen. Denn du argumentierst in etwa so: "Ein Ausnahme-Prozessor hebt die Gesetze der Mathematik auf, weil er keinen DIV-Befehl kennt." So, und das ist irgendwie nicht richtig.
Klar, eine ALU ist dafür da um schneller mal eine Division zu machen. Aber ich wende die ALU nur dann an, wenn es auch ins mathematisch passt. Wenn es nicht passt, muß ich ein Software-DIV benutzen. Wenn ein C++ Compiler das nicht macht, ist der Compiler für ernsthafte Anwendungen unbrauchbar.
Ich habe hier ein ARM-Buch (Advanced Risc Maschine Prozessor) von einem der ARM-Mitentwickler. Und dieser stellt auch ein Software-DIV vor, das den fehlenden DIV-Befehl im ARM kompensiert. Nicht aus Jux und Dollerei, sondern damit man vernünftig dividieren kann. Trotzdem kommt in dem Buch die ALU des ARM nicht zu kurz. Aber ich werde mich hüten das Software-DIV nicht zu benutzen. Vorallem, was macht man denn mit MS-Excel auf den ganzen PocketPCs oder die Palms, die ja einen ARM (StrongARM) drin haben? Rechnen die alle falsch, weil es kein DIV in Hardware gibt?
Überleg nochmal was du hier eigentlich versuchst durch zusetzen. Das kann nicht gut sein. Und ich hoffe, das kein enrnsthafter Compiler bei Divisionen ausschliesslich die ALU in Anspruch nimmt.
-
net schrieb:
also ich finde das seltsam. seit wann kann jeder selber definieren was bei einer division herauskommt?
Das ist nicht "falsch"! Wenn bei Modulo was negatives rauskommt, das ist eigentlich unmathematisch. Korrekt wäre:
- a % b € {0 ... b-1}
- a/b = c mit c*b + rest = asiehe http://de.wikipedia.org/wiki/Kongruenz_(Zahlentheorie)
Das ist halt dort so. Es hat mir selber nicht gefallen, es hat mich Zeit gekostet. Wir mögen beide das verbreitetere System lieber. Warum willst du jetzt mit mir über diesen Prozessor streiten?btw: man kann nicht alle / durch bitshifts ersetzen. malnehmen aber geht.
Wo habe ich das behauptet? Nirgendwo.
Artchi schrieb:
Optimizer! Deine Ansicht ist wirklich merkwürdig und ich kann dir hier auch nicht zustimmen. Denn du argumentierst in etwa so: "Ein Ausnahme-Prozessor hebt die Gesetze der Mathematik auf, weil er keinen DIV-Befehl kennt." So, und das ist irgendwie nicht richtig.
Ähm ne, sowas habe ich nicht gesagt. Ich habe gesagt, der Standard garantiert mir keine bestimmte Ganzzahlen-Arithmetik, das könnte problematisch sein, wenn man von "write once, run everywhere" ausgeht, was angeblich in C++ so toll ist.
Artchi schrieb:
Überleg nochmal was du hier eigentlich versuchst durch zusetzen.
Ich will was durchsetzen?

Artchi schrieb:
Das kann nicht gut sein. Und ich hoffe, das kein enrnsthafter Compiler bei Divisionen ausschliesslich die ALU in Anspruch nimmt.
Hoffe ich auch nicht. Aber die Garantie habe ich nicht. Hast du vergessen, worum es hier ging? Es ging um die Garantie, dass eine Division so abläuft, wie ich es erwarte und die gibt mir C++ nicht. Ich finde das schlecht, du sagst, die Compiler machen das schon "richtig". Ist aber nicht immer so, aber zumindest wäre es immer möglich. Solange das aber nicht spezifiziert ist, garantiert es dir der Standard zumindest nicht. Ganz einfach. Schau im Standard selber nach, wenn du es nicht glaubst.
So, jetzt bauen, wir mal den ganzen Stack wieder ab. Der Standard garantiert dies also nicht (hast du inzwischen nachgeschaut), also funktioniert "write once, run anywhere" nicht zwangsläufig. Du brauchst Compiler, die das nach deinen Wünschen richten, denn nicht jeder standardkonforme C++ Compiler muss es so machen, obwohl zwei Compiler völlig standardkonform sind, können sie unterschiedliche Programme erzeugen. Hui.
-
Optimizer schrieb:
Korrekt wäre:
- a % b € {0 ... b-1}
- a/b = c mit c*b + rest = adas ist ja auch okay so, aber wenn b vom betrag her grösser ist als a, dann ist c immer 0. der rest kann natürlich negativ sein, wenn a selber negativ ist. um auf dein beispiel mit dem komischen prozessor zurückzukommen: -1/10 ist 0 rest -1 und nicht -1 rest 0. das kann der doch nicht einfach vertauschen.
-
net schrieb:
Optimizer schrieb:
Korrekt wäre:
- a % b € {0 ... b-1}
- a/b = c mit c*b + rest = adas ist ja auch okay so, aber wenn b vom betrag her grösser ist als a, dann ist c immer 0. der rest kann natürlich negativ sein, wenn a selber negativ ist. um auf dein beispiel mit dem komischen prozessor zurückzukommen: -1/10 ist 0 rest -1 und nicht -1 rest 0. das kann der doch nicht einfach vertauschen.
Ne, einfach vertauschen tut er es auch nicht.
Es kommt -1 bei der Division raus und Rest 9. Einen Rest von -1 gibt es nicht, denn er liegt nicht in { 0 ... b-1 }.
-
das heisst: es fehlt uns noch eine dritte regel, um integer-division und modulo eindeutig zu machen. das ist ja grausam!
-
Optimizer schrieb:
Höh? Weil es nicht abgedeckt ist, ist es egal?
Exakt! Wenn ich auf einem System nicht so arbeiten kann, wie es der Standard vorschreibt, dann ist mir bewusst, dass ich nicht plattformunabhängig bin. In so einem Fall ist es mir persönlich egal, wenn ich Code habe, den ich auf anderen Systemen nicht einfach so wiederverwenden kann. Ich glaube aber auch nicht, dass ich mit irgendeiner Sprache Anwendungen schreiben kann, die wirklich auf _allen_ Systemen laufen.
Optimizer schrieb:
Ja sind sind eindeutig implementation-defined definiert.
Warum behauptest du, das sei irrelevant? Es ist äußerst unglaubwürdig, "write once, run anywhere" zu postulieren und dann zu behaupten dass Unterschiede in der Arithmetik irrelevant sind. Unterschiede in der Arithmetik verändern das Verhalten deines Programms und sind für die Semantik eines Programm höchst relevant. Du musst es umschreiben, damit es sich auf der neuen Plattform wie gewohnt verhält.Ersten, du denkst zu viel low-level. Wir reden hier immer noch über C++ und nicht über Assembler. Und zweitens, es gibt keine Unterschiede in der Arithmetik, höchstens Spezialfälle. Wie ich schon sagte, die Operatoren sind eindeutig definiert. Hier nur mal ein kleiner Auszug als Beispiel:
The binary * operator indicates multiplication.
Multiplikation bedeutet nunmal Multiplikation. Und ich verstehe das im mathematischen Sinne. Kann sein, dass du das anders verstehst. Ich kenne allerdings nichts anderes. Letztendlich bedeutet das, dass zB 5 multipliziert mit 3 immer 15 ergibt. Nicht 14 und auch nicht 16, sondern exakt 15. Wie letztendlich die Darstellung der Werte auf Bitebene aussieht oder wie die Prozessorbefehle für die Rechnung aussehen, sind mir doch vollkommen egal. Es mag ja sein, dass es CPUs gibt, die solch exotische Ergebnisse wie bei deinem Beispiel ausspucken. Dass es mathematisch trotzdem korrekt ist, darum hat sich der Compiler zu kümmern. Wie er das macht und welche Kombinationen von Befehlen er benutzt, ist seine Sache. Ich sag es nochmal, wir reden bei C++ immer noch von einer Hochsprache und nicht von irgendwelchen Assembler Exzessen. Und sollte ein Compiler das nicht packen, dann, wie Artchi schon sagte, ist er nicht brauchbar.
Optimizer schrieb:
Darauf wollte ich nicht hinaus. Die Header können unterschiedlich implementiert sein, z.B. könnte die Implementierung von <string> den Header <cstring> inkludieren, bei einem anderen Compiler aber nicht. In einem Programm, wo ich jetzt <string> inkludiere, steht mir dann strcpy() vielleicht zur Verfügung, vielleicht auch nicht.
Das ist doch vollkommen bedeutungslos. Du hast meinen Beitrag überhaupt nicht verstanden. Der Standard spezifiziert für alles Mögliche die zugehörige Headerdatei. Wenn du also strcpy() brauchst, dann hast du gefälligst <cstring> einzubinden. <string> interessiert hier keine Sau.