C++-Codebeispiel Phase 1
unter GNU/Linux-Systemen mit GCC –
    aus früherem Programmieren in C++
Inhaltsverzeichnis zu JMB's Seite
    zur Phase1 des Programmierens in C++
    unter GNU/Linux-Systemen
 
Makefiles und
      das Utility make
Beim Programmieren ist der Gebrauch
eines Makefiles (das vom Utility
 make verwendet wird,
siehe Verwendung unterhalb des Makefile‑Beispiels;
vgl. GNU Autoconf) in jedem Fall
sinnvoll,
da dies die nötigen Eingaben
auf ein sinnvolle Maß reduzieren kann
(vgl. kleine Einführung für C und Makefiles,
umfangreichere Einführung in Makefiles,
O'Reilly-Einführung in Makefiles) –
hier ein sinnvolles kleines Beispiel für Makefile:
# ******************************************************************************
# * 'Makefile' des Verzeichnisses '~/mycpp/jmb/'                               *
# *                                                                            *
# * J.M.B.  [URL: https://www.jmb-edu.de/cpp_programming.html#makefileexamp]   *
# *                                                                            *
# * Lizenz:   (c) 2019 unter GPLv3: https://www.gnu.org/licenses/gpl-3.0.txt   *
# *                                                                            *
# * Erstellung:           05.08.2019                                           *
# *                                                                            *
# * Letzte Umgestaltung:  04.09.2019  (Phase 1; vgl. Phase 2 vom 03.09.2019)   *
# ******************************************************************************
# * Was man unter `mach alles' verstehen soll (z.B. mehrere Programme setzen):
all:            example
# * Sprungpunkt fuer das Programm (wie es heißt und was damit passieren soll):
example:        example.cpp
                g++ example.cpp -o example
# * Editieren:
edit:
                -vim example.cpp
# * Binary aufrufen:
run:
                -./example
# * Hausputz:
clean:
                -rm -f core *.o *.bak *~
# * Fruehlingsputz (auch Binary wird geloescht):
superclean:     clean
                -rm -f example
# * Sicherung:
backup:         clean
                -cd .. ; tar cfvz ~/Downloads/mycpp_jmb.tgz jmb/ ; cd jmb
# Zu beachten ist, dass nach "LABEL:" bzw. am leeren Zeilenanfang Tabs
# stehen muessen - Leerzeichen funktioniert nicht!
Nun kann mit make example
(aktuell identisch mit make all)
das Beispielprogramm example.cpp übersetzt werden,
der Hausputz macht aktuell noch nichts
(da core, *.o und *.bak nicht existieren),
make superclean
 löscht das Binary
(d.h. die ausführbare Datei
 in Maschinensprache),
und make backup
 erstellt ein Backup des Verzeichnisses jmb.
Noch wirkt es als nur geringe Ersparnis,
aber schon aufwendig ausgeklügelte Compiler-Flags
oder mehrere zu übersetzende Module bringen dadurch
eine enorme Erleichterung sowie Ordnung, Dokumentation
und Übersicht.
Aber man sieht, dass man den Namen nicht mehr
kennen muss;
man geht ins Projektverzeichnis,
editiert die Quelldatei (wenn es nur eine ist,
sonst braucht man geeignete Label)
mit make edit,
 übersetzt den Code mit make all und ruft zum Test
 das Binary mit make run auf
 (vgl. zugehöriges Programm).
Das Makefile steht unten
mit dem Beispielprogramm example.cpp
und dem resultierenden Binary example
zum direkten
Download bereit.
Vorstellen eines Beispiel‑Programms in C++
Quelltext 
/******************************************************************************
 * C++-Programm 'example.cpp' im Verzeichnis '~/mycpp/jmb/'                   *
 *                                                                            *
 * Funktion:    "Zerlegung einer Zahl in ihre Primfaktoren"                   *
 *                                                                            *
 * J.M.B.   [URL: https://www.jmb-edu.de/cpp_programming.html#progcppexamp]   *
 *                                                                            *
 * Lizenz:  (c) 2019  unter GPLv3: https://www.gnu.org/licenses/gpl-3.0.txt   *
 *                                                                            *
 * Erstellung:           05.08.2019                                           *
 *                                                                            *
 * Letzte Umgestaltung:  04.09.2019  (Phase 1; vgl. Phase 2 vom 03.09.2019)   *
 ******************************************************************************
 */
# include <iostream>                      // fuer std::cin, std::cout, std::endl
# include <string>                        // fuer std::stoi
# include <math.h>                        // fuer sqrt
/* Gebrauch von ANSI-Farben in kompatiblen Terminals:
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Effekt          Code   |  Farbe   Vordergrund Hintergrund |  ASCII 27 = \033
 * zurücksetzen      0    |  schwarz       30         40     |   = ESC-Zeichen
 * fett/hell         1    |  rot           31         41     |
 * unterstrichen     4    |  gruen         32         42     | Z.B. hell rot
 * invertiert        7    |  gelb/orange   33         43     |      auf schwarz
 * fett/hell aus    21    |  blau          34         44     |   "\033[4;31;40m"
 * unterstri. aus   24    |  magenta       35         45     |
 * invertiert aus   27    |  cyan          36         46     | Reset: "\033[0m"
 *   * Just play ! *      |  weiss/grau    37         47     |  * Have fun! *
 */
#define RESET             "\033[0m"          /* Reset to Defaul: zuruecksetzen*/
#define ULLWHITEONYELLOW  "\033[1;4;37;43m"  /* unterstrichen weiss auf orange*/
#define ULLYELLOWONGREEN  "\033[1;4;33;42m"  /* unterstrichen gelb auf gruen  */
#define ULLYELLOWONYELLOW "\033[1;4;33;43m"  /* unterstrichen gelb auf orange */
#define ULLREDONBLACK     "\033[1;4;31;40m"  /* unterstrichen rosa auf schwarz*/
void primeFactors(int n)               // Eigene Funktion zur PF-Ausgabe
{
  using std::cout;                     // cout bedeutet nun std::cout
  using std::endl;                     // endl bedeutet nun std::endl
  cout << "Primzahlfaktoren von " << n << " sind:\n";
  /* 1. Schritt: */
  // Anzahl 2-en ausgeben, durch die n (vor 1. Schritt) dividiert werden kann
  while (n%2 == 0)                     // wenn bei Division kein Rest
  {
    cout << "2, ";                     // jeder Faktor wird ausgegeben
    n = n/2;
  }
  /* 2. Schritt: */
  // n (Anfang 2. Schritt) muss nun ungerade sein - Primfaktoren 2 wurden
  // entdeckt, somit kann man immer eine Zahl uebergehen, daher i=i+2
  for (int i = 3; i <= sqrt(n); i = i+2)
  {
    // Solange n durch i teilbar ist, wird i ausgegeben (analog 2 oben)
    while (n%i == 0)                   // wenn bei Division kein Rest
    {
      cout << i << ", ";               // jeder Faktor wird ausgegeben
      n = n/i;
    }
  }
  /* 3. Schritt: */
  // Wenn for bis i = Wurzel n (n nach 1. Schritt) nicht n=1 (Ende 2. Schritt)
  // liefert, muss n der letzte fehlende Primfaktor der Zerlegung sein
  if (n > 2)
  {
    cout << n << ".";                  // Ausgabe n, da letzter fehlender PF
  }
  cout << endl;
}
int main(int argc, const char* argv[]) // Hauptfunktion bei Aufruf-Parameter
{ /* Begruessung */
  std::cout << ULLYELLOWONGREEN << " * Programm '" << argv[0] << "' zur Ausgabe der Primfaktoren *" << RESET << "\n";
  /* Zahl ermitteln, die in PFs aufgespalten werden soll */
  int wert = 0;
  if (argc > 1)                        // Wurde neben Aufrufnamen ein Parameter
  {                                    //   angegeben?
    wert = std::stoi(argv[1]);         // Dann sollte dies die Zahl sein.
    if (wert < 2)                      // Zahlen kleiner 2 machen keinen Sinn!
    {
      std::cout << ULLREDONBLACK << "Fehler:" << RESET << " Der Aufrufparameter war kleiner als 2!\n";
    }
  }
  while (wert < 2)                     // Bis wert mindestens 2 ist einlesen
  {
    std::cout << "Gib eine ganze Zahl > 1 ein: ";
    std::cin  >> wert;                 // Eingabewert in Variable wert lesen
    if(!std::cin)                      // Lese-Status pruefen ...
    {
      std::cout << ULLREDONBLACK << "Fehler:" << RESET << " Unerlaubte Eingabe!\n";
      return 1;                        // Abbruch mit Fehlercode 1
    }
  }
  /* PFs ermitteln und mit "," getrennt ausgeben */
  primeFactors(wert);                  // Funktionsaufruf fuer PFs
  /* Verabschiedung */
  std::cout << ULLWHITEONYELLOW << " * That's all, folks! " << ULLYELLOWONYELLOW << ";)" << ULLWHITEONYELLOW << " * -<(c) J.M.B. 2019, GPLv3>~-" << RESET << "\n";
  return 0;            // Uebergabewert (= Fehlercode) an Betriebssystem/Shell
}
/******************************************************************************
 * Das war's - ein erstes kleines Programm - nicht zu trivial ...    :))      *
 ******************************************************************************
 */
Erläuterung zum Quelltext
 ✯ Neu 09/2019 ✯ 
Die Phase 2 wurde am 03.09.2019 abgeschlossen –
der neue Quellcode (vergrößert von 104
auf aktuell 775 Zeilen;
also wieder größer als das
bereits am 23.08.2019
überarbeitete Makefile  😳 ; von 41
auf nun 139 Zeilen und auch größer als die GPLv3‑Lizenz mit 674 Zeilen)
mit den Erklärungen
ist nun auf der Phase 2‑Seite
zu finden ...
und es hat sich viel geändert:
Umstellen auf unsigned long long
zur Zerlegung größerer Zahlen,
Abfangen von (ich hoffe  😀 )
allen Eingabefehlern,
Ausgabeumleitung inkl. Schreiben in eine Datei
mit genauem Zeitstempel im Namen,
viele Flags z.B. mit inverser oder
monochromer Bildschirmausgabe,
Ausgabe eines Hilfstextes und ANSI-Steuercodes
über konstante String-Variablen,
übersichtlichere Ausgabe der Primfaktoren,
flexiblere Eingabe mit beliebigen Trennzeichen
sowie erweiterte Kommentare ...
Das Programm ist mit Phase 2 weit genug gediehen,
um damit einen C++-Einstiegskurs sinnvoll leiten
zu können.  😤 
Da die hier dargestellte Phase 1
deutlich kompakter ist,
kann diese auch zuerst gelesen werden,
erst danach die deutlich erweiterte Fassung und
Erklärung zu Phase 2.
Es gibt einiges zu beachten, bis man
mit dem Quelltext etwas anfangen kann:
  -  Kommentare: 
      Alles von //
      bis zum Zeilenende wird vom Compiler ignoriert
      (z.B. Zeile 16 oder 44),
      ebenso alles zwischen /* und */ (z.B. Zeilen 1-14
      oder Zeile 73; vgl. Kommentar‑Arten unten).
      Hier sollen Kommentare verwendet werden,
      die den Quelltext auch nach Monaten
      bis Jahren schnell verständlich machen sollen.
      
      Man sollte sich merken, dass bei C und C++
      als Kommentar immer der Slash / mit einem weiteren Zeichen
      (genauer // bzw.
      /* ... */)
      kombiniert wird –
      bei Shell-Skripten bzw. Makefiles ist es
      das Doppelkreuz (oder hash) #,
      bei 📜LATEX
      das Prozentzeichen %,
      bei 🌐HTML
      <!-- ... -->
      (vgl. Kommentarbeispiele aus Wikipedia). 
  -  Hauptteil:  Jedes C++/C‑Programm
      enthält genau eine main-Funktion
      (im obigen Beispiel Zeile 72;
      hier in der komplizierten Fassung
      unter Heranziehen von mit dem Aufruf
      mitgegebenen Parametern).
      Diese Funktion entspricht
      dem aufgerufenen Programm –
      alles weitere muss von dort aufgerufen werden,
      wie im Beispiel die Funktion primeFactors
      (in Zeile 96).
      Will man Aufrufparameter ignorieren, reicht ein einfaches:
      int main()                             // Hauptfunktion ohne Aufruf-Parameter
      Die Hauptfunktion main sollte
      mit return 0
      abgebrochen werden, was das sofortige Programmende
      bedeutet mit Übergabewert 0
      für alles OK, jede andere Zahl
      (aus Kompatibilitätsgründen
      besser nur bis 127,
      zumeist aber 1,
      bedeutet einen Fehler{code},
      den man in der Shell [unter Linux meist
      die Bash, zu überprüfen
      über echo $SHELL
      mit typischer Ausgabe:
      /bin/bash] aufrufen kann:
      ./example; echo
      "Fehlercode: "$?). 
  -  Präprozessor:  Alle Zeilen,
      die mit Doppelkreuz #
      beginnen, werden vom Präprozessor ausgeführt,
      noch bevor der Compiler seine Arbeit aufnimmt.
      #include weist diesen an,
      die anzugebende Standard-Bibliothek
      (im obigen Beispiel Zeilen 16-18;
      hier mit im Kommentar
      angegebenem Verwendungszweck; diese Dateien sollten sich
      im Suchpfad des Compilers befinden) oder auch
      eine weitere Quelltextdatei im aktuellen Verzeichnis
      (#include "meinModul.hpp";
      also doppelte Anführungszeichen
      statt spitze Klammern)
      einzubinden oder bestimmte Konstanten zu definieren
      (Textersetzung; im obigen Beispiel Zeilen 32-36
              für ASCII-Steuercodes zur Farbwahl).
 
  -  Struktur: 
      Je nach Projekt
      kann der Programmierstil
      deutlich variieren.
      Man sollte sich einen aussuchen und
      bei eigenen Projekten durchhalten,
      so dass man intuitiv Fehler finden kann.
      Bei existierendem Code sollte man sich
      anpassen –
      oder alles umschreiben.
      Bei einem Team sollte man sich möglichst
      auf den Code-Stil einigen
      (siehe auch C++‑Code‑Standards von Standard C++ Foundation, Google, GitHub, geosoft, KDE-Framework|-Libs|Qt, Bjarne Stroustrup's C++ Style and
      Technique FAQ;   
      und C-Code-Standards von GNU und Linux).
      Hier habe ich (fast) alles auf Deutsch
      kommentiert, natürlich ist
      bei internationalen Projekten Englisch angesagt.
      
      a) Zusammengehörigkeit:
      Man sieht, dass {...} bestimmte Blöcke
      zusammen gehören (z.B. Zeilen 39+70, 54+61,
      oder 57+60),
      ebenso dass ...;
      eine Anweisung mit Ende
      bezeichnet (z.B. Zeilen 40, 47
      oder 48; diese Anweisungen werden immer nacheinander
      abgearbeitet – bei Ausdrücken erlebt man
      Überraschungen: hier kann der Compiler
      optimieren) oder dass (...) Ausdrücke beinhalten,
      die z.B. wahr oder falsch sein können
      (Typ bool
      mit Literalen true
      {=1; ggf. auch  
      eine größere Zahl} und false {=0},
      z.B. Zeilen 45, 65 oder 77).
      Nach if muss
      kein Leerzeichen / Blank folgen, { kann direkt nach der Verzweigungs-
      oder Schleifenanweisung kommen.
      Dass hier zugehörige
      geschweifte Klammern die selbe Einrückung haben
      (also untereinander stehen)
      oder niedere Blöcke
      genau zwei Leerzeichen mehr eingerückt sind,
      ist meine Präferenz, auch dass ich nie
      Tabulatoren gebrauche (die leider
      im Makefile Pflicht sind).
      Gebrächlich sind 2 oder 4
      (ganz selten, z.B. dem Linux-Kernel,
      auch 8) Blanks oder ein Tab
      als Einrücktiefe.
      
      b) Kommentar-Arten:
      Vermeidung von Kommentaren der Art /* ... */
      hat den Vorteil,
      dass man dann mit diesem Stil
      große Bereiche auskommentieren kann (vgl. Kommentarabschnitt oben).
      
      c) Namenskonventionen:
      Bei Variablen klein beginnen und dann CamelCase:
      anzahlErfolgterAufrufe
      (bzw. bei Klassenvariablen
      mit Underscore _
      abschließen: anzahlErfolgterAufrufe_),
      bei Funktionen wie Variable
      oder auch snake_case:
      wer_findet_funktion(),
      einfache Typen klein mit Unterstrich und Endung:
      adress_typ,
      Klassen groß beginnen mit CamelCase,
      Konstanten, Enum-Elemente und Makros groß mit Unterstrich:
      SMILEY_FROWNING.
   -  Algorithmus: 
      Als Mathe-Lehrer, der den Schülern
      ab der Klassenstufe 6 beibringt,
      eine Bruchaufgabe sei nur
      bei vollständig gekürztem Bruch
      auch vollständig gelöst und
      somit die volle Punktzahl wert,
      ist ein Programm zur Ausgabe der Primfaktoren
      (PFs) natürlich naheliegend. 😉 
      Was passiert aber mathematisch
      in der Funktion primeFactors:
      Schritt 1 (Zeilen 45‑49):
      Die eigentlich zu zerlegende Zahl n
      (hier als Aufruf-Parameter übergeben,
      Zeile 79, oder im laufenden Programm eingegeben,
      Zeile 88)
      wird zuerst durch 2 geteilt (halbiert),
      bis dies nicht mehr restfrei
      geht (d.h. die verbleibende Zahl
      ist ungerade und ist das neue n,
      wenn das ursprüngliche n
      gerade war).
      Die Variable n ist immer der Quotient,
      in dem noch nicht getestete Faktoren
      stecken können. Bei jedem gefundenen PF
      gibt es einen neuen Wert für n,
      der sich durch Teilen mit dem gefundenen PF
      ergibt (dies gilt auch für den folgenden
      Schritt 2).
      Schritt 2 (Zeilen 53‑61):
      Nun wird nacheinander die zuvor erhaltene
      ungeraden Zahl n
      durch Zahlen i von 3
      bis zu sqrt(n)
      [d.h. square root (n) =
      Wurzel (n) = √n]
      jeweils so oft
      wie restfrei möglich geteilt
      (analog Schritt 1),
      wobei nur ungerade i getestet werden.
      Hierzu sind ein paar Bemerkungen
      zum besseren Verständnis nötig:
      
        - Da bereits der Primfaktor 2
         in Schritt 1 bearbeitet wurde, muss hier
         mit i = 3 begonnen werden.
         - Es müssen nur ungerade Zahlen
         getestet werden (dies wird in Zeile 53
         durch i=i+2 erreicht),
         denn außer 2 sind alle anderen geraden Zahlen
         nicht prim. Zudem wurde durch Schritt 1
         eine ungerade Zahl n erzwungen, so dass
         die geraden Zahlen keine Divisoren i
         für Teilen ohne Rest darstellen.
         - Da der Laufindex inkrementiert wird,
         d.h. sich von klein zu groß wandelt,
         werden Nicht-Primzahlen keine Teiler i
         sein können, da diese Faktoren besitzen,
         um die n bereits beraubt wurde.
         - Hier darf n als am Ende
         von Schritt 1 eingefroren betrachtet werden:
         Wurzel n wäre die größte Zahl,
         die zweimal als Faktor in n stecken kann.
         Eine Zahl größer Wurzel (n)
         kann damit nur einmal in n stecken.
         Diese als einzige von Schritt 2
         nicht behandelte Möglichkeit
         behandelt Schritt 3.
      
 
      Wenn sich durch diese for-Schleife
      am Ende n = 1 ergibt
      (n = 2 ist nicht möglich
      wegen Schitt 1, daher ist (n > 2)
      in Zeile 65 in Ordnung),
      dann ist die Primfaktorzerlegung
      bereits geschafft.
      Ansonsten kommt nun
      Schritt 3 (Zeilen 65‑69):
      Wie in Punkten 3. und 4.
      von Schritt 2 ausgeführt, 
      kann n, wenn es nicht 1 ist,
      nur eine Primzahl sein, die größer als
      √n ist.
      Es gilt also nur noch, diese Primzahl n
      der Liste hinzuzufügen.
      Fertig! 😎  
  -  Lizenz und Urheberrecht: 
      Wenn man privat Code schreibt, besitzt man
      das Copyright und sollte dies
      auch anmerken. Dies gibt das Recht,
      den Code zu verkaufen, aber natürlich ebenso,
      diesen im Form von Freier Software der Allgemeinheit
      zu überlassen
      (Copyleft), so dass niemand
      diesen Code missbrauchen kann,
      sondern nur abändern und ebenfalls
      im Quellcode der Allgemeinheit zur Verfügung
      stellen muss.
      Dies macht die GNU General Public License: GPL,
      deren jüngste und mächtigste Variante
      zur Befreiung der Anwender die GPLv3 ist. 
      Der von mir nur gelinkte Text
      wird normalerweise dem Software-Quelltext
      als Datei beigelegt.
      Hier bedeutet mein Copyright nur,
      dass ich es geschrieben habe und die Nutzung freigebe –
      die Basis-Struktur kam aus einem Beispiel meiner 1. Literaturangabe
      (S. 63, Listing 4.2), 
      der Algorithmus ist wohl bekannt und im Netz
      vielfach leicht zu finden, ebenso die ANSI-Farbsequenzen, die ich schon
      Ende der 1980-er in Tubo Pascal verwendete.
      Nur die spezielle Gestaltung
      ist somit mein Werk.
      Nichts hier ist also ein Copyright
      (Urheberschaft macht bei sehr Einfachem
      wenig Sinn; wenn das mal die Patentämter
      [bzw. die verantwortliche Legislative]
      begreifen würden) oder
      eine Lizenz wert ... es soll nur
      als Beispiel dienen,
      wie man mit eigener Software umgehen sollte.
 
  -  Feinheiten: 
      So, wie die Farbcodes im Teminal über ANSI-Escape-Sequenzen eine neue Farbe festlegen (Kommentar und Festlegung
      in Zeilen 20-36,
      Anwendung in Zeilen 74+82+91+98),
      so gibt es auch in String-Angaben bzw. allgemein
      in C/C++ Escape-Sequenzen,
      z.B. um einen Zeilenumbruch: \n (new line;
      vgl. Zeile 42+74+82+91+98), ein Unicode-Zeichen
      über \Uhhhhhhhh
      zu bewirken oder
      auch das doppelte Anführungszeichen: "
      zu maskieren, das ja als Beginn- bzw. Endemarke
      eines Strings dient und somit im String
      als \"
      dargestellt werden muss.
      Die Escape-Sequenzen beginnen immer
      mit einem Rückwärtsschrägstrich /
      Backslash: \.
      Im Übrigen werden Escape-Sequenzen
      auch in Druckersprachen
      wie ESC/P (Epson) oder
      PCL (HP) verwendet,
      wenn keine Seitenbeschreibungssprachen wie PostScript
      verwendet wird.
      
      Eine Vereinfachung ist
      in Zeilen 40+41 zu finden, so dass der Namespace
      für die beiden angegebenen Funktionen
      nicht mit std::
      ausgewiesen werden muss.
      Stattdessen könnte man auch in einer Zeile
      für alle Funktionen
      der Standardbibliothek schreiben:
        using namespace std;                 // fuer std::cout und std::endl - aber auch bei anderen wirksam
      Diese allgemeine Änderung sollte aber eher
      vermieden werden, insbesondere wenn in main
      und damit global umdefiniert,
      weil hier Mehrdeutigkeiten
      eingeführt werden könnten.
      Daher lieber nur für häufig
      aufgerufene Bibliotheks-Funktionen in einer Funktion
      umdefinieren wie im Listing gezeigt. 
  -  Kommt noch was?: 
      Nicht alles
      ist erklärt ... und wird es
      wohl auch nie (auch wenn ich
      auf Hinweise eingehe).
      Dafür sei die Literaturliste
      und eine Internetrecherche empfohlen.
      Ich beabsichtige, noch einiges
      zu ergänzen –
      und auch am Code deutliche Änderungen
      einfließen zu lassen,
      auch wenn die Basisfunktionalität
      so erhalten bleiben soll.
      Daher habe ich hier die Phase 1
      (vom 08.08.2019)
      dieses Programms eingefroren.
      So wie auch der unten angegebene Download
      diese Fassung auch nach Änderungen der aktuellen Fassung
      weiterhin anbieten wird.
      Ideen für Änderungen
      hätte ich genug ...
      auch für ganz andere Programme ...
      oder einen Programmierkurs für Heranwachsende,
      der sich an einen 📢Vortrag
      anschließen könnte.
 
Ergänzungen 
Wie man nun auf der Kommandozeile mit dem Programm
umgeht, d.h. die einzelnen Programmierschritte auslöst:
den Quelltext editiert, diesen übersetzt und
das ausführbare Programm aufruft,
kann man oben beim Makefile nachlesen.
Hier die Ausgabe im xfce4-terminal
(nach bewusst falschem Startparameter -5 und dann Eingabe von 999):
Das Beispielprogramm steht mit dem Makefile
zum direkten Download
weiter unten bereit.
Zum Binary, d.h. der Datei
des ausführbaren Programms in Maschinencode,
noch ein paar Infos
bzw. wie man sich diese beschafft:
$ ls -al example
-rwxrwxr-x 1 jmb jmb 19240 Aug  6 19:14 example
# d.h. 19249 Byte = 18,8 kB Größe
$ file example
example: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d90c0ad815b0b065ff826a7b39ee71a153341497, for GNU/Linux 3.2.0, not stripped
$ strings example
# Ausgabe aller Zeichenketten (Strings) des Executables (viel)
$ readelf -x .rodata example
# Anzeigen der statischen Strings
$ nm example
# Auflisten der Symbole
$ readelf -s example
# Anzeigen der Symbole
$ readelf -h example
# Ausgabe des ELF (Binärformat unter Linux) - Headers
$ readelf --relocs example
# Klären, ob das Binary ein positionsunabhängiges Executable ist bzgl. der Bibliotheken.
$ ldd example
# Liste dynamisch gelinkter Bibliotheken (hier sechs: linux-vdso.so.1, libstdc++.so.6, libm.so.6, libgcc_s.so.1, libc.so.6, /lib64/ld-linux-x86-64.so.2)
$ ldconfig -p | grep NAME_BIBLIOTHEK
# Nachschauen, ob eine bestimmte Bibliothek auf dem System installiert ist, z.B. bei `ldconfig -p | grep libm.so.6' u.a. `... => /lib/x86_64-linux-gnu/libc.so.6'.
$ /lib/x86_64-linux-gnu/libc.so.6
# liefert am Anfang: 'GNU C Library (Ubuntu GLIBC 2.29-0ubuntu2) stable release version 2.29.' auf Xubuntu 19.04.
$ objdump -d example
# Disassemblieren des Binary bzw. des Object Files (*.o)
$ strace ./example
# Lässt das Programm ablaufen und berichtet, was es dabei tut.
Dies sind ein paar Beispiele,
wobei zumeist auf die GNU Binary Utilities
(kurz binutils, ebenso Name des Pakets,
in dem neben Assembler as und Linker ld
diese Werkzeuge für ausführbare Dateien
enthalten sind; diese werden, wie bereits ausgeführt,
typischerweise gemeinsam mit gcc,
make und
gdb verwendet;
vgl. Homepage sowie Dokumentation
zu GNU Binutils) zurückgegriffen wurde.
Wer das Makefile,
den Quelltext
des obigen C++‑Beispielprogramms und das Executable
für Linux haben möchte,
kann es einfach als gezippte Tar‑Datei
jmb_added_for_cpp_programming_phase1.tgz (7,8 kB,
 Fassung vom 06.09.2019)
downloaden und an passender Stelle
zum neuen Unterverzeichnis jmb_phase1
mit den drei Dateien
(Makefile, example und
 example.cpp)
entpacken über:  
tar xvfz jmb_added_for_cpp_programming_phase1.tgz.
Siehe auch Link zum Download
der aktuellen Fassung der Phase 2 vom 03.09.2019.
Link zum 🐧persönlichen Hintergrund bzgl.
 GNU/Linux.
Link zu 🌠meiner generellen Motivation.
Link zur Hauptseite des 💾Programmierens
 in C++.
Bei Fragen / Problemen mit dieser Seite bzw.
meiner Webpräsenz kontaktieren Sie mich bitte:
      E-Mail:  📧jmb@jmb-edu.de
©️ 1987‑2025  
         
Bitte beachten Sie hierzu auch mein 📄Impressum.
                 
[Zurück zur 🏁Startseite]
  | Erste Fassung: | 30.  | Juli  | 2019 | 
  | Letzte Änderung:  | 19.  | Juli  | 2025 |