Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Compilieren

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
04.08.2019, 10:46 Uhr
m1992



Moin!


Es geht um das Compileren von C++ bzw Assembler Code.

Ist es eventuell effektiver, wenn der C++ Compiler den binary Code nicht optimiert, sondern den C++ Code in Assembler übersetzt und dann assembliert/optimiert?

Mein Ziel ist es, die Binärgröße zu verrringern und die Ausführungsgeschwindigkeit zu erhöhen.

Und natürlich von Erfahrungen / Einblicke zu erhalten



Danke
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
05.08.2019, 10:03 Uhr
ao

(Operator)



Zitat von m1992:
Ist es eventuell effektiver, wenn der C++ Compiler den binary Code nicht optimiert, sondern den C++ Code in Assembler übersetzt und dann assembliert/optimiert?

Wahrscheinlich nicht oder nur marginal. Die Optimierung findet im Compiler statt, weil der die Code-Strukturen analysieren und Optimierungsmöglichkeiten finden kann. Wenn der Code einmal in Assembler übersetzt ist, ist dieses Wissen verloren.


Zitat:
Mein Ziel ist es, die Binärgröße zu verrringern und die Ausführungsgeschwindigkeit zu erhöhen.

Handelt es sich um ein Embedded-System mit limitiertem Speicher?

Dieser Post wurde am 07.08.2019 um 17:03 Uhr von FloSoft editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
05.08.2019, 12:32 Uhr
m1992




Zitat von ao:


Zitat:
Ist es eventuell effektiver, wenn der C++ Compiler den binary Code nicht optimiert, sondern den C++ Code in Assembler übersetzt und dann assembliert/optimiert?

Wahrscheinlich nicht oder nur marginal. Die Optimierung findet im Compiler statt, weil der die Code-Strukturen analysieren und Optimierungsmöglichkeiten finden kann. Wenn der Code einmal in Assembler übersetzt ist, ist dieses Wissen verloren.



- Danke für die Antwort.

Mir stellt sich die Frage, wieso ein "hello world" Programm in Assembler / (C) beziehungsweise C++ als Binary (Windows/exe bzw Linux Distribution) unterschiedlich groß sind (Dateigröße/ (Geschwindigkeit?))

Natürliche haben diese Programmiersprachen andere Abstraktionsschichten, "Ausrichtung" beziehungsweise Bibliotheken.

Wieso "kann" der Compiler nicht das "gleiche Ergebnis" ausgeben?



C++:
Mein Ziel ist es, die Binärgröße zu verrringern und die Ausführungsgeschwindigkeit zu erhöhen.


Zitat von ao:
Handelt es sich um ein Embedded-System mit limitiertem Speicher?


Ab und zu programmiere ich in Assembler bzw C für Atmen Atmega und ARM Prozessoren.

Mir geht es um das Verständnis, warum der Compiler nicht alles, was nicht benötigt wird, außen vor lässt.

Beim Assembler wird nur das übersetzt, was (wirklich) benötigt wird. Wird in den angesprochen Programmiersprachen dies durch den Standad/Struktur verhindert?


Danke

Dieser Post wurde am 07.08.2019 um 17:03 Uhr von FloSoft editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
05.08.2019, 14:15 Uhr
ao

(Operator)



Zitat von m1992:
Beim Assembler wird nur das übersetzt, was (wirklich) benötigt wird. Wird in den angesprochen Programmiersprachen dies durch den Standad/Struktur verhindert?

Ja. Du hast in C(++) immer eine gewisse Laufzeitumgebung zur Verfügung. Dazu gehört Speicherverwaltung (Stack, Heap), Ein- und Ausgabe, Initialisierung globaler Daten, der Sprung in die main() und zurück und so weiter.

Auch wenn ein Programm das nicht oder nur rudimentär braucht (weil es nur "Hello World" ausgibt), ist es trotzdem immer vorhanden, weil jedes Programm, das eine sinnvolle Aufgabe erfüllen soll, das dazu haben muss. Es lohnt sich einfach nicht, die Umgebung so kleinteilig zu konfigurieren, dass für die Super-Trivialfälle (die zu trivial sind, um etwas Sinnvolles zu tun) noch mehr weggelassen werden kann.

Aus dem Grund braucht man auch einen ATMega mit mindestens ein paar Bytes RAM, um ein C-Programm starten zu können. Assembler-Programme laufen dagegen auch auf den RAM-losen Devices (nur mit Registern) - war zumindest früher mal so ...

Dieser Post wurde am 05.08.2019 um 14:18 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
08.08.2019, 22:08 Uhr
Hans
Library Walker
(Operator)



Zitat:
Assembler-Programme laufen dagegen auch auf den RAM-losen Devices (nur mit Registern) - war zumindest früher mal so ...

Soweit ich weis, ist das bei den Tiny-ATs immer noch so.
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
09.08.2019, 07:02 Uhr
m1992




Zitat von ao:
[quote m1992]Beim Assembler wird nur das übersetzt, was (wirklich) benötigt wird. Wird in den angesprochen Programmiersprachen dies durch den Standad/Struktur verhindert?

Ja. Du hast in C(++) immer eine gewisse Laufzeitumgebung zur Verfügung. Dazu gehört Speicherverwaltung (Stack, Heap), Ein- und Ausgabe, Initialisierung globaler Daten, der Sprung in die main() und zurück und so weiter.

Auch wenn ein Programm das nicht oder nur rudimentär braucht (weil es nur "Hello World" ausgibt), ist es trotzdem immer vorhanden, weil jedes Programm, das eine sinnvolle Aufgabe erfüllen soll, das dazu haben muss. Es lohnt sich einfach nicht, die Umgebung so kleinteilig zu konfigurieren, dass für die Super-Trivialfälle (die zu trivial sind, um etwas Sinnvolles zu tun) noch mehr weggelassen werden kann.

Aus dem Grund braucht man auch einen ATMega mit mindestens ein paar Bytes RAM, um ein C-Programm starten zu können. Assembler-Programme laufen dagegen auch auf den RAM-losen Devices (nur mit Registern) - war zumindest früher mal so ...[/quote]


Danke für die ausführliche Antwort.


Nur zum Verständnis fürnmich noch folgende Fragen:

- Sprünge können doch durch Prozessorbefehle wie "jmp" "ersetzt" werden und sind doch dann nur noch reiner Asm Code?

- Ein- und Ausgabe (etc) können als Assembler Code ausgegeben werden? Dadurch wäre doch "möglich" in dieser Richtung zu optimieren.

- Als Beispiel: Linux bzw Microsoft sind in Assembler/C bzw C++ geschrieben. Dafür sind diese dem entsprechend.
Hingegen sind KolibriOS bzw MenuetOS komplett in Assembler und kleiner/ schneller (zeitlich und "gefühlt")


Mir geht es nur um das Verständnis, warum ein "Hello world" bzw andere Programme in Assembler/C und C++ unterschiedlich groß und Geschwindigkeit haben (mit und ohne Optimierung)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
09.08.2019, 13:44 Uhr
ao

(Operator)



Zitat von m1992:
- Sprünge können doch durch Prozessorbefehle wie "jmp" "ersetzt" werden und sind doch dann nur noch reiner Asm Code?

Sprünge - meinst du goto-Befehle? Die sollte man in Hochsprachen nur in ganz seltenen Fällen einsetzen.


Zitat:
- Ein- und Ausgabe (etc) können als Assembler Code ausgegeben werden? Dadurch wäre doch "möglich" in dieser Richtung zu optimieren.

Möglich, ja. Aber eine in C geschriebene Routine läuft nicht nur auf x86-PCs, sondern auch auf Macintosh, iPhone, Android (um mal nur die bekanntesten zu nennen). Bzw. kann von jedem, der C kann, angepasst werden. Das sind auch wichtige Aspekte: Einmal fertige Arbeit wiederzuverwenden und nicht für jeden Handgriff einen Spezialexperten zu brauchen.


Zitat:
- Als Beispiel: Linux bzw Microsoft sind in Assembler/C bzw C++ geschrieben. Dafür sind diese dem entsprechend.
Hingegen sind KolibriOS bzw MenuetOS komplett in Assembler und kleiner/ schneller (zeitlich und "gefühlt")

Ich zitiere mal von der MenuetOs-Startseite: "Menuet beruht nicht auf UNIX oder dem POSIX Standard, noch basiert es auf einem anderen Betriebssystem. Das Designziel ist es die Extra-Schichten zwischen verschiedenen Teilen des Bestriebssystems zu beseitigen, welche normalerweise die Programmierung verkompliziert und Bugs verursacht." - Hervorhebung von mir. Sorry, aber das ist einfach nur zum Lachen. "Extra-Schichten" wie Posix verursachen keine Bugs, sondern sorgen dafür, dass sich jeder Programmierer in jedem Quellcode zurechtfinden kann, weil die Räder eben nicht jedesmal neu erfunden werden und ähnliche Dinge immer ähnlich aussehen.

Und die Grafik von Kolibri und Menuet erinnert mich stark an meine Jugend in den späten 80ern. Vor allem diese Pixelschriften sind ja noch schlimmer als die von Windows 3.0.

Und da wir hier unter Programmierern sind: Wer bisher gedacht hat, das Win32-API von Microsoft wäre kryptisch, der möge sich mal das hier zu Gemüte führen https://www.menuetos.de/dokumente/Systemfunktionen und sich vorstellen, er müsste in diesem Stil ein verkaufbares (d.h. auch im nächsten Jahr noch pflegbares) Programm schreiben.


Zitat:
Mir geht es nur um das Verständnis, warum ein "Hello world" bzw andere Programme in Assembler/C und C++ unterschiedlich groß und Geschwindigkeit haben (mit und ohne Optimierung)

Ich deutete es schon an. In Assembler definierst du ein Stück konstanten Speicher mit dem Inhalt "Hello world", bringst das irgendwie ins Video-RAM und bist fertig.

In C++ hast du (ob du das nun brauchst oder nicht) immer eine Speicherverwaltung, d.h. du kannst Variablen deklarieren, Funktionen aufrufen, Speicher vom Betriebssystem anfordern und vieles mehr. Das wird alles vorbereitet vom sogenannten "Startup-Code", von dem du normalerweise nichts zu sehen kriegst, weil er nämlich als eine Art Vorspann vor der main-Funktion läuft, und auch hinterher und wieder aufräumt.

Da es kein "sinnvolles" C++-Programm gibt, das ohne all das auskommt, ist es eben immer vorhanden, auch wenn man nur Hello world schreiben will.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
11.08.2019, 02:39 Uhr
Hans
Library Walker
(Operator)



Zitat von ao:
Wer bisher gedacht hat, das Win32-API von Microsoft wäre kryptisch, der möge sich mal das hier zu Gemüte führen https://www.menuetos.de/dokumente/Systemfunktionen und sich vorstellen, er müsste in diesem Stil ein verkaufbares (d.h. auch im nächsten Jahr noch pflegbares) Programm schreiben.

Wow! - Das ist x86 32-Bit Code, - also nur auf x86 CPUs lauffähig. Portabilität? - Fehlanzeige!

Anekdote:
Das erinnerte mich an eine Story aus dem Buch "C-Tools", das es in den 80er Jahren mal gab. Darin beschreibt einer, wie er sich hingesetzt hat, um das grösste Projekt der Welt in Angriff zu nehmen. Er schrieb einige Zeilen Assemblercode hin, und begann nachzudenken. Die Überlegungen führten dazu, das Programm schliesslich doch in C zu entwickeln, einfach, weil es einfacher war. Es handelte sich dabei um einen einfachen C-Compiler, den er sinnigerweise dann auch Small-C genannt hat. Standardisiert war da nicht viel, weil es zu der Zeit nur das Buch von K&R gab, aber noch keinen offiziellen Standard vom ANSI. - Der kam erst einige Jahre später.
Anekdote Ende.
Ein Grund also, warum man in einer Hochsprache schreibt, und nicht in Assembler ist der, dass es einfacher ist. Sofern es für die Sprache einen Standard gibt, reicht es aus, etwas einmal zu schreiben. Die Details einer Prozessorarchitektur kann man dem Compiler zu überlassen. Und selbst den Compiler kann (und wird) man zum grössten Teil in einer Hochsprache schreiben. Was man u.U. noch in Assembler schreibt, sind ganz fundamentale Dinge, wie mathematische Operatoren für die Grundrechenarten. Oder wenn man irgendwo an bestimmten Stellen, wo es extrem auf Geschwindigkeit ankommt, auch die letzten Optimierungen einbauen will, die möglich sind. Diese Stellen werden aber vorher mit speziellen Programmen (Profiler) entdeckt, und erst wenn sämtliche Optimierungsoptionen des Compilers ausgereizt sind, man es aber dennoch schneller braucht, kann man hingehen und den Code analysieren, den der Compiler erzeugt hat, um zu sehen, ob da von Hand noch was an Overhead gestrichen werden kann. - An dieser Stelle stellt sich aber auch die Frage, ob man den richtigen Algorithmus gewählt hat, und falls ja, ob man ihn auch optiomal umgesetzt hat? - Wenn eine dieser beiden Fragen mit Nein zu beantworten ist, macht auch die beste Handoptimierung das Programm an dieser Stelle nicht mehr schneller als es im Idealfall sein könnte. Als Beispiel sei das Sortieren von Daten genannt. Dafür gibt es verschiedene Algorithmen, wovon der Schnellste der Quicksort ist. Wenn man einen anderen Algorithmus als den Quicksort wählt, ist das Programm langsamer. Der Grund liegt in der Natur der Algorithmen.
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
11.08.2019, 03:32 Uhr
Hans
Library Walker
(Operator)



Zitat von m1992:
- Sprünge können doch durch Prozessorbefehle wie "jmp" "ersetzt" werden und sind doch dann nur noch reiner Asm Code?


Die Frage ist: was für Sprünge meinst Du jetzt?
So sprünge wie "Goto"?
Oder indirekte Sprünge wie sie etwa bei if-else- oder case-Konstruktionen vorkommen?
Bei ersteren kann der Compilker sicherlich Befehle wie "JMP" einsetzen. Bei letzteren findet man neben bedingten aber auch unbedingte Sprünge, wie "JMP" einer ist.


Zitat von m1992:
- Ein- und Ausgabe (etc) können als Assembler Code ausgegeben werden?

Was für Ein- und Ausgaben?
Ein Zeichen auf dem Bildschirm ausgeben, oder ein Byte an eine Hardware Schnittstelle ausgeben, wo man es z.B. durch LEDs angezeigt bekommt?
Ersteres war schon auf den Heimcomputern der 80er Jahre eine sehr lange Routine (Funktion), die aus vielen Zeilen Assembler(!) Code bestand. Es gilt da nämlich, die Cursorposition zu beachten, die die Zeile und die Spalte, an der ein Zeichen erscheinen soll, beschreiben. Unter einer GUI kommt dann noch dazu, in welchem Fenster, wo das Fenster innerhalb des darstellbaren Bereichs liegt und so Dinge wie der verwendete Zeichensatz, die gewünschte Zeichengrösse, und Attribute wie fett, kursiv oder unterstrichen. Du siehst hier jetzt hoffentlich, dass Bildschirmausgabe etwas hochkomplexes ist. Das kann ein einzelner I/O-Befehl nicht leisten.
Und da ist ja auch noch das Interface der Grafikkarte! - Da jede Grafikkarte bzw. jeder Grafikchip den Bildschirm auf seine eigene Art und Weise verwaltet und darstellt, ist man letztlich gezwungen, das Application Programming Interface (API) vom Treiber der Grafikkarte zu verwenden.

Anders stellt sich die Sache bei Schnittstellen dar, die direkt nach draussen führen. Die kann man über die I/O-Befehle der CPU ansprechen. ABER: Bei Multitaskingsystemen wie Windows und Linux/Unix wird man dazu trotzdem eine Systemfunktion aufrufen müssen, die die Sache übernimmt. Denn diese Systeme erlauben es nicht, dass jedes belibige Programm irgendwas in die Schnittstellenports schreibt. Und das ist auch richtig so, denn zum einen kann es sein, das ein anderes Programm gerade auch auf den Port schreiben will, zum anderen kann es aber auch sein, dass ein Programm dazu überhaupt keine Berechtigung hat, weil der Nutzer dieses Programmes (der vor dem Rechner sitzt) diese Berechtigung auch nicht hat.
Solche Dinge überwachen die Betriebssysteme immer, wenn sie Multitasking unterstützen. Die reinen Assembler-I/O-Befehle wird man also letztlich im Treiber für die Schnittstelle finden, weil das der Ort ist, wo sie hin gehören.
Ach ja, und dann kann es auch noch sein, dass die CPU sich weigert, I/O-Befehle auszuführen, weil sie unterschiedliche Privilegstufen dafür hat. Bei x86-CPUs sind das die Ringe, auf denen Programme laufen. Da gibt es Befehle, die laufen nur auf höchster Privilegstufe. Wenn ein Programm von einer niedrigeren Privilegstufe solche Befehle ausführen will, provoziert es 'ne Hardware-Exception. - Es wird also von der CPU abgewürgt.

Alles klar?
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
12.08.2019, 09:20 Uhr
ao

(Operator)



Zitat von Hans:
Die reinen Assembler-I/O-Befehle wird man also letztlich im Treiber für die Schnittstelle finden, weil das der Ort ist, wo sie hin gehören.

Und auch da werden sie immer seltener. Schon deshalb, weil es immer weniger Software gibt, die mit einem einzigen Zielsystem im Sinn geschrieben wird. Sowohl Windows als auch Linux (nur zwei prominente Beispiele) laufen beide nicht nur auf x86-PCs, sondern auch auf Mobil- und Embedded-Systemen mit ARM-Prozessor. Da kannst du keinen Treiber gebrauchen, der in Assembler geschrieben ist. Nur das, was unbedingt nötig ist, wird noch in Assembler programmiert, alles andere ist C oder eine andere Hochsprache.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: