[🛈Start+]   [🥋Trad. Taekwon-Do+]   [🧮Mathematik]   [📙Forschung & Lehre+] [🐧GNU/Linux+]
[🔑Impressum+]   [🛀Autogenes Training+]   [💡Physik]   [⚙️Technik+]   [💾Progs: C+++]
Sprache:  [GB-NA-Flagge]  [🔭Astronomie] [📜LATEX]   [🕹️Spiele+]

JMB-LogoJMB-AvatarBlue Ribbon Icon (Freie Rede)

C++-Codebeispiel Phase 1

unter GNU/Linux-Systemen mit GCC – aus früherem Programmieren in C++

[💾Progs: C++]   [🖪Progs: Alter C++‑Code]

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:

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):
[Output des C++-Beispiel-Programms]
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-2021 JMB           Bitte beachten Sie hierzu auch mein 📄Impressum.                   W3C: Valid HTML 4.01 Transitional

[Zurück zur 🏁Startseite]
Erste Fassung:30. Juli 2019
Letzte Änderung: 31. März 2021