[🛈Start+] | [🥋Trad. Taekwon-Do+] | [🧮Mathematik] | [📙Forschung & Lehre+] | [🐧GNU/Linux+] |
[🔑Impressum+] | [🛀Autogenes Training+] | [💡Physik] | [⚙️Technik+] | [💾Progs: C+++] |
Sprache: ![]() |
[🔭Astronomie] | [📜LATEX] | [🕹️Spiele+] |
![]() | ![]() | ![]() |
[💾Progs: C++] | [🖪Progs: Alter C++‑Code] |
# ******************************************************************************
# * '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 2; vgl. Phase 1 vom 08.08.2019) *
# ******************************************************************************
# * Dafuer sorgen, dass 'all' und 'clean' auch dann ausgefuehrt werden,
# wenn die jeweils entsprechende Datei existieren sollte:
.PHONY: all clean exampd exampf example_debug example c cf
# * Beim Hilfstext nicht durch doppelte Ausgabe verwirren, also das Kommando
# nicht vor der Ausfuehrung ausgeben:
.SILENT: info help h
# * Definitionen von sinnvollen Compiler-Flag-Kombinationen als Variable
# (hier ist noch viel Raum fuer Verbesserungen - nur ein Anfang):
# o Debug Modus: optimierte Debugging-Faehigkeit mit allen Standard- sowie
# allen Extra-Warnungen (zum Lernen beim Edit-Compile-Debug-Zyklus):
cppflagsd = -Og -Wall -Wextra
# o Space Modus: optimiert bzgl. Groesse und alles von -O2, das dem nicht
# zuwider laeuft (falls man es mal brauchen sollte ;):
cppflagss = -Os
# o Final Modus: optimiert haerter bzgl. Kompilierzeit und Geschwindigkeit
# des Binarys.
cppflagsf = -O2
# * Fuer Namensgebung der Backup-Datei Datum und Zeit als String besorgen:
bckdate := $(shell date +%Y%m%0e%0k%M%S)
bckname := ~/Downloads/mycpp_jmb_$(bckdate).tgz
humdate := $(shell date +%a.,\ %0e.%m.%Y,\ %0k:%M:%S)
humdatedate := $(shell date +%a.,\ %0e.%m.%Y)
humdatetime := $(shell date +%0k:%M:%S)
# ** Das nun kommende erste Target wird ausgefuehrt, wenn 'make' ohne
# Argument, d.h. der Angabe des Targets, aufgerufen wird:
# * Hilfstext (zur Uebersicht, was alles gemacht werden kann; siehe Screenshot unten):
info help h:
-echo "Zur Zeit sind die folgenden Parameter moeglich: ^***************"
-echo " ep = ed = edit = e: * Hilfs-Text *"
-echo " Quelltext des Programms mit vim editieren, * zu 'make' *"
-echo " em: * von J.M.B. *"
-echo " Editieren von 'Makefile' mit vim, ^*********** *"
-echo " exampd = example_debug = c: * *"
-echo " Kompilieren & Linken von 'example_debug' & 'ls -l' vom Binary, * *"
-echo " exampf = example = cf: * *"
-echo " Kompilieren & Linken von 'example' und 'ls -l' vom Binary, * *"
-echo " all {= exampd & exampf}: * *"
-echo " Erzeugen beider Binaries: 'example_debug' & 'example', * *"
-echo " r: * *"
-echo " Aufrufen von 'example_debug args' & Fehlercode ausgeben, * *"
-echo " run: * *"
-echo " Aufrufen von 'example args' - danach Fehlercode ausgeben, * *"
-echo " clean: * *"
-echo " Hausputz (: 'example_debug' loeschen), * *"
-echo " superclean: * *"
-echo " Fruehlingsputz (% 'clean' + loeschen von 'example'), * *"
-echo " backup = bck **** [jmb-edu.de] * *"
-echo " Erstellen einer tgz-Sicherung, * **************** *"
-echo " help = h = info = '' {d.h. ohne Target}: * Have Fun with GNU! *"
-echo " Diesen Hilfstext ausgeben. ***********************"
-echo " == GNU 'make' ${MAKE_VERSION} gestartet am $(humdatedate), um $(humdatetime) Uhr ! =="
# * Was man unter `mach alles' verstehen soll (z.B. mehrere Binaries bauen;
# dieses Target ist zumeist das erste und wird bei 'make' ausgefuehrt):
all: exampd exampf
# * Sprungpunkt/Target fuer das Programm (Name und was damit passieren soll):
# -a) Optimiert fuer optimale Debbuging-Faehigkeit, allen Standard-
# sowie den Extra-Warnungen (zum Lernen beim Edit-Compile-Debug-Zyklus):
exampd c example_debug: example.cpp
-g++ $(cppflagsd) example.cpp -o example_debug
-ls -l example_debug
# - b) Optimiert fuer Kompilierzeit und Geschwindigkeit des Binarys:
exampf cf example: example.cpp
-g++ $(cppflagsf) example.cpp -o example
-ls -l example
# ... fuer weitere Verbesserungen siehe z.B.:
# https://developers.redhat.com/blog/2018/03/21/compiler-and-linker-flags-gcc/
# * Editieren:
# o ... des Programm-Quellcodes:
ep ed edit e:
-vim example.cpp
# o ... des Makefiles:
em:
-vim Makefile
# * Binary aufrufen, danach Fehlercode auslesen (0 = OK; sonst = KO):
r:
-./example_debug $(filter-out $@,$(MAKECMDGOALS)); echo "Fehlercode: "$$?" !"
# * Fuer andere als die ausgewiesenen Targets mache nichts
# (wegen r/run-Optionen noetig, sie sonst je eine Fehlermeldung gaeben) -
# Vorsicht: 'make quark' macht nichts - auch keine Fehlermeldung!:
%:
@:
run:
-./example $(filter-out $@,$(MAKECMDGOALS)); echo "Fehlercode: "$$?" !"
# * Waere Compilieren und Ausfuehren gewuenscht, dies auskommentieren:
#cr: c r
# * Hausputz (Problemreste und Debug-Binary werden geloescht):
clean:
-rm -f core *.o *.bak *~ example_debug
# * Fruehlingsputz (auch das finale Binary wird nun geloescht):
superclean: clean
-rm -f example
# * Sicherung (als gezipptes tar-Archiv):
backup bck: clean exampd
-echo "Sichere in: '$(bckname)' ..."
-cd .. ; tar cfvz $(bckname) jmb/ ; cd jmb
# Zu beachten ist, dass nach "TARGET:" bzw. am leeren Zeilenanfang Tabs
# stehen muessen - Leerzeichen funktioniert nicht - ebenso zwischen
# multiple targets, die von einem anderen (hier 'all' oder 'bck')
# aufgerufen werden!
# Somit darf man auch nicht Copy&Paste machen (Blanks werden dann durch
# Leerzeichen ersetzt), sondern kopieren oder ueber 'tar' sichern ...
# ******************************************************************************
# * Das war's ... Viel Spass beim eigenen Experimentieren und Programmieren ! *
# ******************************************************************************
Nun kann mit make example
(oder make example_debug;
per make all
wird beides gemacht) das Beispielprogramm example.cpp übersetzt werden,
der Hausputz macht aktuell noch wenig
(da core, *.o und *.bak nicht existieren;
lediglich example_debug
würde gelöscht),
make superclean
löscht zusätzlich das Binary
(d.h. die ausführbare Datei
in Maschinensprache),
und make backup
erstellt ein Backup des Verzeichnisses jmb.
Noch wirkt es nicht wie eine notwendige Ersparnis,
aber schon aufwendig ausgeklügelte Compiler-Flags
(vgl. insb. Optimierungs-Optionen oder
Warnungen – oder auch die Red Hat Empfehlungen für Compiler-
und Linker‑Parameter der GCC)
oder mehrere zu übersetzende Module bringen dadurch
eine enorme Erleichterung sowie Ordnung, Dokumentation
und Übersicht.
Der Hauptzweck von make
liegt im automatischen Erzeugen lauffähiger Programme,
bei der ggf. viele Dateien übersetzt und
gelinkt werden müssen, d.h. Compiler und Linker
stehen im Zentrum.
Zudem hat man heute viele Auswahlmöglichkeiten,
welche Anforderungen das Binary erfüllen soll.
Diese werden über Parameter,
den sogenannten Compiler‑Flags,
GCC mitgeteilt.
Wenn man Fehler finden will, sollten Debugginghilfen
eingebaut sein, die sich eher nachteilig
auf die Größe und/oder die Ablaufgeschwindigkeit
auswirken werden.
Daneben kann man die Ablaufgeschwindigkeit
optimieren – soweit,
dass man ggf. bei einigen Binaries Fehler provoziert
(d.h. nicht nur harte sondern sogar
agressive Optimierung –
ohne Rücksicht auf Verluste).
Im Gegenzug können auch seltene Ausnahmebedingungen
abgefangen werden oder Angriffsziele maskiert bzw.
geschützt werden,
was als Härtung des Codes bezeichnet wird –
im Gegensatz zur Härte der Optimierung,
die bei hart sozusagen im gelben Bereich und
bei agressiv im roten liegt (der ggf.
im Beispiel von schnellen 🕹️Spielen mit nicht mehr
perfekter Grafik durchaus akzeptabel sein kann,
bei einem Dateisystem oder einer Datenbank
mit fehlerhafter Verarbeitung aber
inakzeptabel wäre).
Diese Optimierung wird hier grob per Flags
in den Zeile 22‑32 gesteuert und dann
in Zeilen 75‑87 umgesetzt.
if [ -f "$HOME/.alias" ]; then
. "$HOME/.alias"
fi
automatisch aufrufen lassen.
Dann funktioniert auch make run ‑5.
1978 | Buch The C Programming Language: K&R C |
1989 | C Norm ANSI X3.159‑1989: ANSI C / C89 |
1990 | C Norm ISO/IEC 9899:1990: C90 (=C89; mit GCC über -ansi, -std=c90 oder -std=iso9899:1990) |
1995 | Minimale Erweiterung als C Norm ISO/IEC 9899/AMD1:1995: C95 (mit GCC über -std=iso9899:199409) |
1999 | C Norm {u.a. mit Ergänzungen von C++} ISO/IEC 9899:1999: C99 {formerly C9X} (mit GCC über -std=c99 oder -std=iso9899:1999) |
2011 | ISO‑Standard {u.a. bessere Kompatibilität mit C++} ISO/IEC 9899/2011: C11 {formerly C1X} (mit GCC über -std=c11 oder -std=iso9899:2011) |
2018 | Minimale Erweiterung als C Norm ISO/IEC 9899/2018: C18 bzw. C17 |
2022 | ?? Erweiterung als C Norm ISO/IEC 9899/2022: {anfänglich C2x} C22 |
1985 | Erste Version von C++ |
1989 | Version 2.0 von C++ |
1998 | C++ Norm ISO/IEC 14882:1998:
C++98 🎇Neu🎉: Templates, STL mit Containern und Algorithmen, Strings, I/O‑Streams |
2003 | Nachbesserung der C++ Norm ISO/IEC 14882:2003: C++03 |
2011 | Modern C++
ISO/IEC 14882:2011: C++11 [ab GCC 4.8.1
und Clang 3.3 unterstützt {aus Linux‑Magazin 12/2017}] 🎇Neu🎉: Vereinheitlichte Initialisierung, Move‑Semantik, ![]() ![]() |
2014 | 1. Erweiterung von C++11 ISO/IEC 14882:2014:
{anfänglich C++1y} C++14 [ab GCC 5.0
und Clang 3.4 unterstützt {aus Linux‑Magazin 12/2017},
ab GCC 6.1 Default] 🎇Neu🎉: Verallgemeinerte Lambda‑Funktion, Verallgemeinerte constexpr‑Funktion, Erleichterte Lesbarkeit durch ' in Zahlenliteralen: 22'324'573UL, Einführung des Binärliterals: 0b0101'1110, Typdefinition bei Nutzer‑definierten Literalen: als String "123"s, Imaginärteil complex imaginaer {6.9i}; oder Zeitdauern mit h, min, s, ms, us und ns (das doppelt definierte s macht keine Probleme, da das eine auf Strings und das andere auf Zahlen operiert), auto als Rückgabetyp von Funktionen, rand() wird nicht mehr empfohlen, neues Attribut deprecated, Reader Writer Locks, Ergänzung der Standard‑Bibliothek (z.B. std::make_unique) |
2017 | 2. Erweiterung von C++11 ISO/IEC 14882:2017:
{anfänglich C++1z} C++17 [ab GCC 7
und Clang 5 unterstützt {aus Linux‑Magazin 12/2017},
seit GCC 9 nicht mehr experimentell,
Default ab GCC 11 {siehe Phoronix, 27.06.2020 bzw. Phoronix, 25.04.2021}] 🎇Neu🎉: Zur besseren Compile‑Zeit tragen bei: Fold Expressions sowie constexpr if für bedingte Übersetzung, if und switch mit Initialisieren (ähnlich wie die Laufvariable in for), Structured Binding, neuer Typ std::byte zum byte‑weisen Zugriff auf den Speicher, Entfernung von auto_ptr (C++11 std::unique_ptr ist Ersatz) und Trigraphs (drei Zeichen, die Sonderzeichen darstellen, falls diese über Tastatur nicht eingebbar sind, z.B. ??= für #), std::stringview, Parallele Algorithmen der STL, Dateisystem‑Bibliothek, neue generische Container std::any, std::optional, std::variant |
2020 | 3. Erweiterung von C++11 ISO/IEC 14882:2020:
{anfänglich C++2a} C++20 (vgl. Artikel auf Heise Developer
von Rainer Grimm zu C++20, jeweils vom
28.10.2019 + 04.11. + 11.11. + 18.11. +
25.11. + 02.12. + 09.12. + 16.12. + 23.12.2019 +
12.01.2020 + 20.01. + 27.01. + 02.02. + 10.02. +
17.02. + 24.02. + 02.03. + 09.03. + 16.03. +
23.03. + 30.03. + 06.04. + 13.04. + 20.04. +
27.04. + 04.05. + 11.05. + 18.05. + 25.05. +
01.06. + 08.06. + 15.06. + 22.06. + 29.06. +
06.07. + 13.07. + 20.07. + 27.07. + 03.08. +
10.08. + 17.08. + 24.08. + 14.09. + 21.09. +
28.09. + 05.10. + 12.10. + 19.10. + 26.10. +
02.11. + 09.11. + 16.11. + 23.11. + 30.11. +
07.12. + 14.12. + 21.12.2020 + 11.01.2021 + 18.01. +
25.01. + 01.02. + 08.02. + 15.02. + 22.02. +
01.03. + 08.03. + 15.03. + 22.03. + 29.03. +
05.04. + 12.04.2021:
Die vier großen Neuerungen + Überblick zur Kernsprache + Überblick zur Bibliothek + Überblick zur Concurrency + Zwei Extreme und die Rettung
dank Concepts + Concepts – die Details + Concepts –
die Placeholder Syntax + Concepts – Syntactic Sugar + Concepts – was wir
nicht bekommen + Vordefinierte Concepts + Concepts definieren + Die Concepts Equal und Ordering definieren + Die Concepts SemiRegular und
Regular definieren + Concepts in C++20: Eine Evolution oder
eine Revolution? + Die Ranges‑Bibliothek + Funktionale Pattern mit der Ranges‑Bibliothek + Pythonisch mit der Ranges‑Bibliothek + Pythons range‑Funktion,
die zweite + Die map‑Funktion von Python + Coroutinen – ein erster Überblick + Mehr Details zu Coroutinen + Ein unendlicher Datenstrom mit Coroutinen + Thread-Synchronisation mit Coroutinen + Coroutinen mit cppcoro + Mächtige Coroutinen
mit cppcoro + Thread‑Pools
mit cppcoro + Die Vorteile von Modulen + Ein einfaches
math‑Modul + Module Interface Unit und
Module Implementation Unit + Module strukturieren + Weitere offene Fragen
zu Modulen + Der Drei‑Weg‑Vergleichsoperator <=> + Mehr Details zum Spaceship‑Operator + Optimierte Vergleiche mit dem
Spaceship Operator + Designated Initializers + Zwei neue Schlüsselwörter in C++20:
consteval und constinit + Die Lösung des Static Initialization
Order Fiasco mit C++20 + Verschiedene Template‑Verbesserungen
mit C++20 + Mächtigere Lambda‑Ausdrücke mit C++20 + Mehr Lambda‑Features
mit C++20 + Neue Attribute mit C++20 + volatile und andere
kleine Verbesserungen in C++20 + Geschützter Zugriff auf Sequenzen
von Objekten mit std::span + constexpr std::vector und
constexpr std::string in C++20 + Neue praktische Funktionen für Container
in C++20 + std::format in C++20 + std::format um benutzterdefinierte
Datentypen erweitern + Noch mehr praktische Werkzeuge
in C++20 + Kalender und Zeitzonen in C++20:
1. Tageszeit + 2. Kalendertag + 3. Umgang mit Kalendertagen + 4. Zeitzonen + Sicherer Vergleich von Ganzzahlen
in C++20 + Prüfen von C++‑Features
mit C++20 + Bit‑Manipulationen mit C++20 + Atomare Referenzen mit C++20 + Synchronisation mit atomaren Variablen in C++20 + Performanzvergleich von Bedingungsvariablen
und Atomics in C++20 + Semaphoren in C++20 + Latches in C++20 + Barrieren und atomare Smart Pointers
in C++20 + Kooperatives Unterbrechen eines Threads
in C++20 + Ein verbesserter Thread
mit C++20 + Synchronisierte Ausgabe‑Streams mit C++20 + C++20: Einfache Futures
mit Coroutinen implementieren + Lazy Futures mit Coroutinen
in C++20 + C++20: Mit Coroutinen einen Future
in einem eigenen Thread ausführen + Ein unendlicher Datenstrom dank Coroutinen
in C++20 + Ein generischer Datenstrom mit Coroutinen
in C++20 + Jobs starten mit Coroutinen
in C++20 + Coroutinen in C++20: Automatisches Fortsetzen
eines Jobs auf einem anderen Thread) 🎇Neu🎉: Module (Alternative zu Headern; Präprozessor wird unnötig), Coroutinen (zur asynchronen Programmierung), Range‑Bibliothek (um Algorithmen der STL direkt auf Container anzuwenden, die Bereichs‑Objekte erlauben Verknüpfungen mit dem Pipe‑Operator und deren Definition auf unendliche Datenströme), Concepts (eine Erweiterung der Templates; siehe C++20‑Konzepte: Neue Wege mit Konzepten, Heise Developer, 08/2021), Contracts (Interfaces für Funktionen/Methoden: Vorbedingungen, Nachbedingungen und Zusicherungen während der Ausführung) {Contracts wurden für den Entwurf genehmigt, danach aber wieder gelöscht – was gut ist, kommt wieder ;} Am 15.02.2020 wurde in Prag abgestimmt, C++20 als DIS (`Draft International Standard') zur endgültigen Zustimmung und Publikation zu schicken (vgl. reddit-Artikel). Er kann nun als abgeschlossen betrachtet werden und die Arbeit am nächsten Standard kann beginnen. Der Entwurf wurde am 05.09.2020 bestätigt (siehe Phoronix, 06.09.2020). Für einen Überblick über C++20 siehe Magazin iX Developer – Modernes C++, 28.09.2020 (vgl. auch Weniger stupide Schreibarbeit: Code reduzieren mit C++20, iX 03/2021). |
2023 | 4. Erweiterung von C++11 ISO/IEC 14882:2023:
C++23
??? erste Vorschläge umfassen: `Modular Standard Library', Bibliotheks-Unterstützung von `Coroutines', `Executors' und `Networking', auf der Sprachseite Intensivierung von `Reflection' inklusive `Introspection', Programmierung zur Compile‑Zeit und Generierung sowie `Pattern Matching' und `Contracts' ... ??? |
/******************************************************************************
* 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: 07.09.2019 (Phase 2; vgl. Phase 1 vom 08.08.2019) *
******************************************************************************
*/
/* Einbau von Bibliotheken der C++-Standardbibliothek: */
# include <string> // fuer std::string {Container-Typ}:
// std::stoi/stoll, std::to_string
# include <vector> // fuer std::vector {Container-Typ}
# include <iostream> // fuer std::cin, std::cout, std::endl
# include <sstream> // fuer std::stringstream/ostringstream
# include <fstream> // fuer std::ofstream (Datei: file)
# include <stdexcept> // exception - zur Ausnahme-Behandlung
# include <cmath> // C-Mathe-Lib in C++ fuer: std::sqrt(l)
# include <ctime> // " std::time_t/struct tm/time/localtime
/* Gebrauch von ANSI-Farben in kompatiblen Terminals:
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Effekt Code | Farbe Vordergrund Hintergrund | ASCII 27 = \033
* zuruecksetzen 0 | schwarz 30 40 | = ESC-Zeichen
* fett/hell 1 | rot 31 41 | Z.B. hell rot
* unterstrichen 4 | gruen 32 42 | auf schwarz
* invertiert 7 | gelb/orange 33 43 | "\033[4;31;40m"
* fett/hell aus 21 | blau 34 44 | Clear Screan:
* unterstri. aus 24 | magenta 35 45 |"\033[2J\033[1;1H"
* invertiert aus 27 | cyan 36 46 | Reset: "\033[0m"
* * Just play ! * | weiss/grau 37 47 | * Have fun! *
*/
// * Globale String-Konstanten zur Festlegung der ANSI-Steuercodes, hier
// * bzgl. STIL_VGFARBE_HGFARBE (siehe Erklaerung oben; Esc=x1B=27=\033):
const std::string // Definition aller ANSI-ESC-Sequenzen / Farben
// Anstelle: '# define RESET "\033[0m"' fuer Praeprozessor nun:
RESET = "\x1B[0m", // Reset to Defaul: zuruecksetzen
CLRSCR = "\x1B[2J\x1B[1;1H", // wie in C++ 'std::system("clear");'
UL_LWHITE_BROWN = "\x1B[1;4;37;43m",// unterstrichen weiss auf orange
LWHITE_BROWN = "\x1B[1;37;43m", // weiss auf braun/orange
UL_LYELLOW_BROWN = "\x1B[1;4;33;43m",// unterstrichen gelb auf braun/orange
LYELLOW_BROWN = "\x1B[1;33;43m", // gelb auf braun/orange
UL_LRED_BLACK = "\x1B[1;4;31;40m",// unterstrichen rosa auf schwarz
LRED_BLACK = "\x1B[1;31;40m", // rosa auf schwarz
LYELLOW_BLACK = "\x1B[1;33;40m", // gelb auf schwarz
UL_LYELLOW_GREEN = "\x1B[1;4;33;42m",// unterstrichen gelb auf gruen
RED_BROWN = "\x1B[31;43m"; // rot auf braun/orange
// * Globale Variable zur Festlegung, ob Ausgabe ohne ANSI-Farben gewuenscht ist
bool farbLos = false; // wird nur von main umgeaendert!
// * Nun eine zweiteilige Funktion zum (ggf. farbigen) Start bzw. Ende ;)
void begruessung (std::ostream& os, bool anfang, std::string prgname)
{ using std::endl; // endl bedeutet nun std::endl
if (anfang) // * anfang: 1 = true (= Begruessung)
{ /* Begruessung */
if (farbLos)
{ // prgname = argv[0], d.h. Aufrufstring
os << " * Programm '" << prgname << "' zur Ausgabe der Primfaktoren *";
os << endl;
} else
{ // prgname = argv[0], d.h. Aufrufstring
os << UL_LYELLOW_BROWN << " * Programm '" << UL_LYELLOW_GREEN << prgname;
os << UL_LYELLOW_BROWN << "' zur Ausgabe der Primfaktoren *" << RESET;
os << endl;
}
} else // * anfang: 0 = false (= Abschied)
{ /* Verabschiedung */
if (farbLos)
{
os << " * Macht's gut, Kinners! \U0001F609 * -<\u00A9 2019 J.M.B., GPLv3\U0001F60E>-";
os << endl;
} else
{
os << UL_LWHITE_BROWN << " * Macht's gut, Kinners! ";
os << LYELLOW_BROWN << "\U0001F609" << UL_LWHITE_BROWN;
os << " * -<\u00A9 2019 J.M.B., GPLv3" << RED_BROWN << "\U0001F60D";
os << UL_LWHITE_BROWN << ">-" << RESET << endl;
}
}
} // Ende: void begruessung (std::ostream& os, bool anfang, std::string prgname)
// * Nun eine Funktion zur Ausgabe von Fehler-Hinweisen:
void meldeInfo (std::ostream& os, bool errMsg, std::string msgStr)
{ using std::endl; // endl bedeutet nun std::endl
if (errMsg) // errMsg = 1: "Fehler: ..."
{ /* ehemals void fehlerInfo (std::ostream& os, std::string fehlerStr) */
if (farbLos)
{
os << " * Fehler: " << msgStr << "!" << endl;
} else
{
os << LRED_BLACK << " * " << UL_LRED_BLACK << "Fehler:" << RESET;
os << " " << msgStr << "!" << endl;
}
} else // errMsg = 0: "Info: ..."
{ /* ehemals void hinweisInfo (std::ostream& os, std::string hinweisStr) */
if (farbLos)
{
os << " * Info: " << msgStr << endl;
} else
{
os << LYELLOW_BROWN << " * " << UL_LYELLOW_BROWN << "Info:" << RESET;
os << " " << msgStr << endl;
}
}
} // Ende: void meldeInfo (std::ostream& os, bool errMsg, std::string msgStr)
void ausgabeInfotext (std::ostream& os, bool hlpMsg)
{
if (hlpMsg) // hlpMsg = 1: Hilfs-Text ..."
{
if (!(farbLos))
os << LYELLOW_BROWN << " * Hilfstext:" << LWHITE_BROWN << "\n";
os << " *******************************************************************\n";
os << " * Generelle Funktion und Spezialparameter des Programms 'example' *\n";
os << " *-===============================================================-*\n";
os << " * Es ist moeglich, als 1. Parameter ein Steuerflag einzugeben: *\n";
os << " * o Keinen Spezialparameter (d.h. kein Steuerflag): *\n";
os << " * Parameter / interaktiv einzugebende Zahlen als Strings holen *\n";
os << " * und nacheinander bearbeiten: jeweils Ganzzahlen zwischen *\n";
os << " * 2 und 18446744073709551615 (2^64-1), auch hex. wie 0x9AFE, *\n";
os << " * in Primfaktoren zerlegen und die Faktoren ausgeben. *\n";
os << " * Alle Nichtzahlen werden ignoriert - sie koennen aber als *\n";
os << " * Zahlentrenner eingesetzt werden (wie 66,0x1B bzw. 66/12/9). *\n";
os << " * Eingabe eines Zeichens: 'H' - Hilfs-, 'V'- Versions-Text und *\n";
os << " * 'B' - beide interaktiv abrufbar, mit '1'/'Q' abbrechen. *\n";
os << " * o -f --file => Ausgabe des Parameter-Teils in eine Datei - *\n";
os << " * eine interaktive Abfrage erfolgt nicht. *\n";
os << " * o -m --mono => Monochromatisch mit Default-Farben vom xterm *\n";
os << " * o -i --inverse => Invertierte Darstellung (mit Nostalgie \U0001F917 ) *\n";
os << " * gelb auf schwarz (wie Turbo Pascal 3.0) *\n";
os << " * o -h --help => Diesen Hilfstext ausgeben und beenden *\n";
os << " * o -v --version => Version, Datum, Autorinfo, Lizenz & beenden *\n";
os << " * o -b -vh -hv => Versions- und Hilfs-Text ausgeben & beenden *\n";
os << " *******************************************************************";
} else // hlpMsg = 1: Versions-Text ..."
{
if (!(farbLos))
os << LYELLOW_BROWN << " * Versionstext:" << LWHITE_BROWN << "\n";
os << " *******************************************************************\n";
os << " * C++-Programm fuer GNU/Linux >example< in Version 2.00 (Phase 2) *\n";
os << " * \u00A9 2019 J.M.B. (URL: https://www.jmb-edu.de/) 03.09.2019 GPLv3 *\n";
os << " * [URL: https://www.jmb-edu.de/cpp_programming.html#progcppexamp] *\n";
os << " *******************************************************************";
}
if (!(farbLos))
os << RESET;
os << std::endl;
} // Ende: void ausgabeInfotext (std::ostream& os)
// * Globale Variable fuer Dateiname
std::string outputFilename = ""; // v- spaeter mit Zeitstempel YYYYMMDDHHMMSS..
std::string myOutputFilename = "PrimZahlZerlegung_JMB.txt";// Ueberschreibschutz
// * Zwei Funktionen zum Erhalt des Datumsstrings (braucht '# include <ctime>'):
std::string addZeroIOD (std::ostream& os, std::string addStr)
{
if (addStr.length() == 1)
{
addStr = std::string("0")+addStr; // ergaenze fuehrende 0 bei einer Ziffer
} else if ((addStr.length() == 0) || (addStr.length() > 2)) // 2 ist OK :)
{
meldeInfo (os, 1, "Falsche Stringlaenge in addZeroIOD!");
return ""; // macht nichts kaputt - Fehler sichtbar
}
return addStr;
} // Ende: addZeroIOD (std::ostream& os, std::string addStr)
std::string getDatStr (std::ostream& os)
{ using namespace std; // sollte vermieden werden; hier klein
tm *nun; // ein struct fuer Zeitangaben: tm_*
time_t now = time(0); // Sekunden seit 00:00, Jan 1 1970 UTC
nun = localtime(&now); // Konvertieren in Kalenderzeit
int dateYear = 1900 + nun->tm_year; // Jahr: seit 1900 (= 0)
int dateMonth = 1 + nun->tm_mon; // Monate: 0-11
int dateDay = nun->tm_mday; // Tage: 1-31
int timeHour = nun->tm_hour; // Stunden: 0-23
int timeMin = nun->tm_min; // Minuten: 0-59
int timeSec = nun->tm_sec; // Sekunden: 0-60 (Schaltsekunde)
string dateTime = to_string (dateYear); // Start dateTime mit Jahreszahl
string addStr = addZeroIOD (os, to_string (dateMonth)); // Monat zweist. ..
dateTime += addStr; // .. in addStr und diesen anfuegen
addStr = addZeroIOD(os, to_string (dateDay)); // Tag zweistellig ..
dateTime += addStr; // .. in addStr und diesen anfuegen
addStr = addZeroIOD(os, to_string (timeHour)); // Stunden zweistellig ..
dateTime += addStr; // .. in addStr und diesen anfuegen
addStr = addZeroIOD(os, to_string (timeMin)); // Minuten zweistellig ..
dateTime += addStr; // .. in addStr und diesen anfuegen
addStr = addZeroIOD(os, to_string (timeSec)); // Sekunden zweistellig ..
dateTime += addStr; // .. in addStr und diesen anfuegen
return dateTime; // Zeitstring als YYYYMMDDHHMMSS zurueck
} // Ende: std::string getDatStr (std::ostream& os)
// * Globale Variable fuer Primfaktorliste:
// * Funktion suchePrimFaktoren bestueckt sie,
// * Funktion ausgabePrimFaktoren liest sie
// * fuer Ausgabe aus und setzt sie zurueck.
std::vector<unsigned long long> wertepfs;
// * Globale Variable, die bei ausgabePrimFaktoren ausgelesen und
// * ausgegeben wird und an deren Ende auch inkrementiert (+1) wird.
unsigned long long anzFaktorZerlegungen = 1;
// * Globale Variablen fuer Eingabe ueber Parameter/Tastatur ...
std::string inputStr = ""; // Einlese-String
std::string::size_type sz = 0; // Entspricht size_t (ein Alias)
// sz dient als Marker fuer StringRest-Kopie in verwandleStringInULL !
// * Funktion zur PF-Ermittlung - der eigentliche Algorithmus (d.h. das Herz)
void suchePrimFaktoren (unsigned long long 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
{
wertepfs.push_back (2); // jeder Faktor wird gemerkt -> wertepfs
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 (unsigned long long i = 3; i <= std::sqrt(n); i = i+2)
{ // .. nach GCC Namspace-Fix sqrtl statt^^^^ verwenden (C++17-Voraussetzung)
// Solange n durch i teilbar ist, wird i ausgegeben (analog 2 oben)
while (n%i == 0) // wenn bei Division kein Rest
{
wertepfs.push_back (i); // jeder Faktor wird gemerkt -> wertepfs
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) // n ist der letzte fehlende PF ...
{
wertepfs.push_back (n); // n wird als PF gemerkt -> wertepfs
}
} // Ende: void suchePrimFaktoren (unsigned long long n)
void ausgabePrimFaktoren (std::ostream& os, unsigned long long wert)
{
int pfanz = 0; // Anzahl Primfaktoren - hier int OK!
std::string pfliststring = " "; // Def.+Initialisierung von String
std::string dummystring = "";
unsigned int curoutstrllength = 0; // Laenge der aktuellen pfliststring-Z.
unsigned int addfutstrlength= 0; // Laenge der naechsten Ergaenzung
const unsigned int maxlength = 75; // Angabe der maximalen Zeilenlaenge - 1
std::string zeilUmbrStr = ",\n * ";
if (!(farbLos))
zeilUmbrStr = ",\n"+LYELLOW_BROWN+" * "+RESET+" ";
for (unsigned long long primfaktor : wertepfs)
{
if (pfanz < 1)
{
pfliststring += std::to_string (primfaktor); // to_string ab C++11
curoutstrllength = pfliststring.length(); // Startlaenge der Zeile
} else // es gab Vorgaenger: +' ,'
{
dummystring = std::to_string (primfaktor);
addfutstrlength = (2+dummystring.length());
if (!(curoutstrllength+addfutstrlength+2 < maxlength))
{
pfliststring += zeilUmbrStr; // Zeilenumbruch + Platz
curoutstrllength = addfutstrlength; // Neuer Start Zeilenlaenge
} else
{
pfliststring += ", "; // Komma + wenig Platz
curoutstrllength += addfutstrlength; // Zeilenlaenge vergroess.
}
pfliststring += std::to_string (primfaktor); // aktuelle PF dem Str. zuf.
}
++pfanz;
}
pfliststring += "."; // Abschlusspunkt
if (pfanz < 2)
{
if (!(farbLos))
{
os << LYELLOW_BROWN << " * " << RESET;
} else
{
os << " * ";
}
os << "Der " << anzFaktorZerlegungen << ". Wert '" << wert;
os << "' ist bereits prim." << std::endl; // \n und Flushen am Schluss
} else
{
if (!(farbLos))
{
os << LYELLOW_BROWN << " * " << RESET;
} else
{
os << " * ";
}
os << " Der " << anzFaktorZerlegungen << ". Wert '" << wert;
os << "' konnte in " << pfanz << " Primfaktoren zerlegt werden:\n";
if (!(farbLos))
{
os << LYELLOW_BROWN << " * " << RESET;
} else
{
os << " * ";
}
os << pfliststring << std::endl; // Liste als Abschluss, \n und Flushen!
} // Angaben x86_64-Linux, signed|uns. int|long|long long ist systemabhaengig:
if (wert == 18446744073709551615ull)// 2^64-1 groesster 64 Bit - Wert!
{
meldeInfo (os, 0, "Ende von 'unsigned long long' erreicht - groesser nur mit Spezial-Libs!");
} else if (wert > 9223372036854775807) // 2^63-1 grosster signed 64 Bit - W!
{
meldeInfo (os, 0, "Hier war 'unsigned long long' statt '>long long<' notwendig!");
} else if (wert > 4294967295) // 2^32-1 grosster unsigned 32 Bit-W!
{
meldeInfo (os, 0, "Hier war 'unsigned long long' statt '>unsigned int<' notwendig!");
} else if (wert > 2147483647) // 2^31-1 grosster signed 32 Bit-W!
{
meldeInfo (os, 0, "Hier war 'unsigned long long' statt '>int<' notwendig!");
} else if (wert > 255) // 2^8-1 grosster unsigned 8 Bit-W!
{
meldeInfo (os, 0, "Hier war 'unsigned long long' statt '>unsigned char<' notwendig!");
} else if (wert > 127) // 2^7-1 grosster signed 8 Bit-W!
{
meldeInfo (os, 0, "Hier war 'unsigned long long' statt '>signed char<' notwendig!");
}
/* Vector wertepfs loeschen, damit Platz fuer neue Eintraege ist */
wertepfs.clear();
++anzFaktorZerlegungen; // Globale Variable als Zaehler: +1
} // Ende: void ausgabePrimFaktoren (std::ostream& os, unsigned long long wert)
// * Diese Funktion loescht fuehrende Zahlen (zu gross fuer ULL), indem diese
// * im Uebergabestring geloescht werden und der Rest uebergeben wird.
// * Fuer vorzeichenlose Ganzzahl-Typen ist die Funktion schon allgemein.
std::string loescheFuehrendeZahlen (std::ostream& os, std::string stringRest)
{
unsigned int stringRestLength = stringRest.length(); // Laenge stringRest
if (stringRestLength == 0)
{ // die Funktion kann mit Leerstring starten und damit enden - kein Fehler!
meldeInfo (os, 1, "Leerstring bei loescheFuehrendeZahlen sollte nicht vorkommen");
return "";
}
if (!(std::isdigit(stringRest[0])))
{
meldeInfo (os, 1, "Aufruf von loescheFuehrendeZahlen mit 1. Zeichen keine Zahl");
return stringRest; // Parameter startet mit Zahl - nix tun
} else
{ // 1. Zeichen [0] wird geloescht - mehr?
for (unsigned int i = 1; i < stringRestLength; ++i)
{ // wieviele Zeichen werden geloescht: i
if (!(std::isdigit(stringRest[i]))) // keine Zahl, dann hier Abbruch
{
return (stringRest.erase(0, i)); // ab 0 {= Anfang}: i Zeichen loeschen
}
}
return ""; // alle Zeichen Zahlen - Leerstring
}
} // Ende: string loescheFuehrendeZahlen (ostream& os, std::string stringRest)
// * Diese Funktion loescht fuehrende Nicht-Zahlen, indem diese im
// * Uebergabestring geloescht werden und der Rest uebergeben wird.
// * Fuer vorzeichenlose Ganzzahl-Typen ist die Funktion schon allgemein,
// * wenn man nicht strenger mit dem Anwender sein will/muss. ;)
std::string loescheFuehrendeNichtZahlen (std::ostream& os, std::string stringRest)
{
unsigned int stringRestLength = stringRest.length(); // Laenge stringRest
if (stringRestLength == 0)
{ // die Funktion kann mit Leerstring starten und damit enden - kein Fehler!
return "";
}
if (std::isdigit(stringRest[0]))
{
return stringRest; // Parameter startet mit Zahl - nix tun
} else
{ // 1. Zeichen [0] wird geloescht - mehr?
if ((stringRest[0] == '-') && (std::isdigit(stringRest[1])))
meldeInfo (os, 1, "Negative Zahlen sind nicht erlaubt: '-' wird verworfen");
for (unsigned int i = 1; i < stringRestLength; ++i)
{ // wieviele Zeichen werden geloescht: i
if (std::isdigit(stringRest[i]))
{
return (stringRest.erase(0, i)); // ab 0 {= Anfang}: i Zeichen loeschen
} else if ((stringRest[i] == '-') && (std::isdigit(stringRest[(i+1)])))
{ // nur bei - Meldung - Rest stumm weg
meldeInfo (os, 1, "Negative Zahlen sind nicht erlaubt: '-' wird verworfen");
} // alles andere wird uebergangen
}
return ""; // alle Zeichen keine Zahlen - Leerstr.
}
} // Ende: string loescheFuehrendeNichtZahlen (ostream& os, string stringRest)
// * Diese Funktion wandelt einen String in die zugehoerige ULL
// * (groesster positiver C++-Standard-Ganzzahltyp) und faengt
// * alle Probleme ab - da negative Werte ohne jede Kennzeichnung
// * unsinnig konvertiert werden, wird zur Eliminierung von '-'
// * die obige Funktion loescheFuehrendeNichtZahlen vorgeschaltet.
// * Sollte diese Funktion in anderem Zusammenhang verwendet werden,
// * darf nicht mehr 0 angemahnt und ansonsten zum Weitermachen verwendet
// * werden, sondern sollte ueber einen Fehlerstatus weitergegeben werden,
// * der ggf. eine globale Variable ist als ullConvErr oder ULL global und
// * den Boolean als Rueckgabe, da eine Funktion nur einen Rueckgabewert
// * hat (wenn man kein Konstrukt uebergeben will) - zudem sollte als
// * Parameter einfach "(std::string teilString)" mitgegeben werden - hier
// * werden globale Variablen wegen komplexer KBD-Schleife verwendet ... -
// * und der Reststring wird in dieser Funktion mit sz beschnittet ... -
// * ansonsten ist die Funktion bereits allgemein.
unsigned long long verwandleStringInULL (std::ostream& os)
{
unsigned long long wert = 0; // Definition mit Startwert: Rueckgabe
try // Solange kein Fehlert auftritt ...
{
wert = std::stoull (inputStr,&sz,0); // ... sollte dies die Zahl sein.
if (wert == 0) // 0 wird sonst verwendet als 'continue'
{
meldeInfo (os, 1, "Es wurde '0' eingegeben"); // 0 bei Faktorzerlegung unsinnig
}
} catch (std::invalid_argument &exc) // --- Erster Handler ...
{
meldeInfo (os, 1, "Ungueltiger Aufrufparameter: nicht in ULL konvertierbar");
inputStr = loescheFuehrendeZahlen(os, inputStr);
return 0; // hier abbrechen, aussen weitermachen
} catch (std::out_of_range &exc) // --- zweiter Handler ...
{ // bei ULL bedeutet ^- dies zu gross - negativ wird nicht erkannt!
meldeInfo (os, 1, "Ungueltiger Aufrufparameter: ausserhalb der ULL-Grenzen (zu gross)");
inputStr = loescheFuehrendeZahlen(os, inputStr);
return 0; // hier abbrechen, aussen weitermachen
} catch( ... ) // ... dritter Handler fuer den Rest.
{
meldeInfo (os, 1, "Seltsames Problem bei der Umwandlung in ULL-Grenzen aufgetreten");
inputStr = loescheFuehrendeZahlen(os, inputStr);
return 0; // hier abbrechen, aussen weitermachen
}
// Nur Loeschen der Zahl bei Ueberlauf/Umwandlung verlaesst zuvor - return 0:
inputStr = inputStr.substr(sz); // inputStr ist nun der Rest ...
return wert;
} // Ende: unsigned long long verwandleStringInULL (std::ostream& os)
// * Nun zwei Funktionen, zuerst werden Kommandozeilen-Parameter gesucht (CLP),
// * dann wird eine Eingabe ueber die Tastatur erbeten und gelesen (KBD).
// * Wegen der zentralen Schleifen stehen sie direkt vor main ...
// Diese Funktion ermittelt die Parameter und wertet diese einzeln als String
// aus, die in jeweils eine oder mehrere Zahlen ueberfuehrt werden,
// die in einer Schleife abgearbeitet werden:
// sie sollen in Primfaktoren zerlegt und so ausgegeben werden.
unsigned long long eingabeCLPZahlZumFaktorisieren (std::ostream& os, int argc,
const char* argv[], bool frstParamUsed)
{
unsigned long long wert = 0; // < 2 ist Fehlercode, > 1 ist ges. Wert
for (int i = 1; i < argc; ++i)
{
if ((i == 1) && (frstParamUsed)) // 1. Parameter "-f" wegwerfen!
{
meldeInfo (os, 0, "1. Parameter enthielt Steuerflag - ist kein Input.");
continue;
}
inputStr = argv[i]; // fuer meine Funktionen editierbar als std::string
// * String muss mit Zahl beginnen, kein '-' oder gar Buchstabe:
inputStr = loescheFuehrendeNichtZahlen (os, inputStr);
while (!inputStr.empty())
{
wert = verwandleStringInULL (os); // inputStr wird verwendet
// * Bedeutet: std::stoull (dummyString,&sz,0) & inputStr.substr(0,sz) kopiert.
if (wert > 1) // OK, wert kann zerlegt werden
{
/* PFs ermitteln und in vector wertepfs speichern */
suchePrimFaktoren (wert);
/* PFs aus wertepfs lesen, mit "," getrennt ausgeben & "." am Ende */
ausgabePrimFaktoren (os, wert);
} else if (wert == 1) // wegen Benchmark auch hier Abbruch
{
meldeInfo (os, 0, "Abbruch des Programms wurde gewuenscht! - Benchmark?");
return 0; // Programmabbruch mit OK-Code gewuenscht
} // = 0 wird nicht behandelt, da verwandleStringInULL Fehler meldet
// * String muss mit Zahl beginnen, kein '-' oder gar Buchstabe:
inputStr = loescheFuehrendeNichtZahlen (os, inputStr);
}
}
if (wert == 0) // wenn nicht ueber return: continue
wert = 5; // uninteressanter wird - unbeachtet
return wert; // Weitergabe der Zahl ...
} // Ende: unsigned long long eingabeCLPZahlZumFaktorisieren (std::ostream& os,
// \ int argc, const char* argv[], bool frstParamUsed)
// Diese Funktion liest bei Bedarf einen Sting, der in eine oder mehrere
// Zahlen ueberfuehrt wird, die in einer Schleife abgearbeitet werden:
// sie sollen in Primfaktoren zerlegt und so ausgegeben werden.
unsigned long long eingabeKBDZahlZumFaktorisieren (std::ostream& os)
{
unsigned long long wert = 0; // < 1 ist falsch - d.h. wiederholen,
// 1 ist Fehlercode zum Programmabbruch,
// > 1 ist gesuchter Wert!
while (wert < 1) // Bis wert mindestens 1 ist einlesen
{
inputStr = "";
// * Eingabe-Aufforderung:
meldeInfo (os, 0, "Spezial: 'H': Hilfe \U0001F198-'B'-'V': Versionsinfo \U0001F6C8 , '1'/'Q': Abbruch \u274C.");
meldeInfo (os, 0, "Gib ansonsten eine ganze Zahl \u2115 in [2;18446744073709551615]\u2705 ein:");
if (farbLos)
{
os << " * ";
} else
{
os << LYELLOW_BROWN << " * " << RESET;
}
os << " \U0001F644 \U0001F635";
os << " \U0001F634 \U0001F612 ";
// * Lese von Tastatur in String:
std::getline(std::cin, inputStr);
if (inputStr.length() == 1)
{
switch (inputStr[0])
{
case 'H': case 'h':
{ // * Hilfsinfo und Abbruch der Funktion mit '5' {= continue}
ausgabeInfotext (os, 1);
return 5;
}
case 'V': case 'v':
{ // * Versionsinfo und Abbruch der Funktion mit '5' {= continue}
ausgabeInfotext (os, 0);
return 5;
}
case 'B': case 'b':
{ // * Versionsinfo und Abbruch der Funktion mit '5' {= continue}
ausgabeInfotext (os, 0);
ausgabeInfotext (os, 1);
return 5;
}
case '1': case 'Q': case 'q':
{ // * Programm-Abbruch: '1' - break kann (wie zuvor: '5') entfallen.
return 0;
} // ein Zweig: 'default : ...' als Joker ist nicht noetig.
}
}
// * String muss mit Zahl beginnen, kein '-' oder gar Buchstabe:
inputStr = loescheFuehrendeNichtZahlen (os, inputStr);
while (!inputStr.empty())
{
wert = verwandleStringInULL (os); // inputStr wird verwendet
// * Bedeutet: std::stoull (dummyString,&sz,0) & inputStr.substr(0,sz) kopiert.
if (wert > 1) // OK, wert kann zerlegt werden
{
/* PFs ermitteln und in vector wertepfs speichern */
suchePrimFaktoren (wert);
/* PFs aus wertepfs lesen, mit "," getrennt ausgeben und "." am Ende */
ausgabePrimFaktoren (os, wert);
} else if (wert == 1)
{
meldeInfo (os, 0, "Abbruch des Programms wurde gewuenscht!");
break;
} // = 0 wird nicht behandelt, da verwandleStringInULL Fehler meldet
// * String muss mit Zahl beginnen, kein '-' oder gar Buchstabe:
inputStr = loescheFuehrendeNichtZahlen (os, inputStr);
}
}
if (wert == 1)
{
wert = 0;
}
return wert; // Weitergabe der Zahl zur Faktorisierung
} // Ende: unsigned long long eingabeKBDZahlZumFaktorisieren (std::ostream& os)
// * Die folgende Funktion enthaelt den Grossteil des ehemaligen Kerns
// * von main, der wegen Uebergabe von ostream nun besser als Funktion
// * aufgerufen werden kann.
// * Es wird die Hauptfunktion als CLP = Parameter-Abfrage und als Schleife
// * KBD als interaktive Tastaturabfrage behandelt und Return-Codes ermittelt.
int abfrageSchleifePFBestimmungAusgabe (std::ostream& os, const int argc,
const char* argv[], bool frstParamUsed)
{
/* Zahl aus Kommandozeilen-Parameter ermitteln,
die im Anschluss in PFs aufgespalten werden soll */
unsigned long long wert = eingabeCLPZahlZumFaktorisieren (os, argc, argv, frstParamUsed);
// * Variablen-Deklaration von wert als Rueckgabewert der beiden
// * Eingabefunktionen; in abfrageSchleifePFBestimmungAusgabe bedeutet:
// * '> 1': continue (Programm laeuft weiter - Tastatureingabe-Schleife),
// * '== 1': Abbruch mit Fehlercode 1 und
// * '== 0': Abbruch gewuenscht, d.h. mit Code 0 fuer alles OK!
// CLP-Einlesen nun beendet ... noch die letzten Auswertungen von wert
if (outputFilename == myOutputFilename)
{ // * Datei-Ausgabe hat keinen KBD-Teil
if (wert > 1) // Keine Abbruchbedingung bislang,
wert = 0; // also regulaeres Ende
meldeInfo (os, 0, "Hier noch zum Abschluss der Versions- und Hilfs-Text des Programms:");
ausgabeInfotext (os, 0); // Versions-Text ausgeben
ausgabeInfotext (os, 1); // Hilfs-Text ausgeben
return wert; // Verabschiedung erfolgt im main-Zweig
}
if (wert == 0) // {(wert < 2): return (wert) ginge auch}
{ // * Abbruch nach CLP gewuenscht (kein KBD) - Benchmark
return 0; // dann Abbruch mit Fehlercode 0
} else if (wert == 1)
{ // Wesentliches Problem
return 1; // dann Abbruch mit Fehlercode 1
} // ausser 0 und 1 bedeutet alles continue
do // Schleife bzgl. Tastatureingabe ...
{
/* Zahl aus Tastatureingabe (KBD; von cin) ermitteln,
die im Anschluss in PFs aufgespalten werden soll */
wert = eingabeKBDZahlZumFaktorisieren (os);
if (wert == 1) // Wesentliches Problem
return 1; // dann Abbruch mit Fehlercode 1
if (wert == 0) // Abbruch durch Eingabe 1 gewaehlt
return 0; // -> Abbruch ohne Fehlercode (0 = OK)
// * Zur Erinnerung, main verabschiedet (ausser Dateiausgabe) und reicht
// * am Ende den Return-Code an das Betriebssystem/xterm/Shell weiter ...
} while (wert > 1); // gleichbedeutend mit !(wert == 1),
// und dies sollte oben abbrechen ...
// *** HIER SOLLTE NICHTS LANDEN - EINFACH DURCHSCHAUEN ...
meldeInfo (os, 1, "Hier sollte - am Ende von abfrageSchleifePFBestimmungAusgabe - nichts landen");
return 1; // Uebergabewert (= Fehlercode) an main
} // Ende: int abfrageSchleifePFBestimmungAusgabe (ostream& os, const int argc,
// \ const char* argv[], bool frstParamUsed)
// * Hauptfunktion - nimmt Parameter entgegen und ermittelt ggf. einen
// * Steuer-Parameter, aendert ggf. die globale Variable farbLos und setzt
// * ggf. die an CLP durchgereichte Variable frstParamUsed (beides passiert
// * nur hier), gibt dann viele Parameter wie genauer outputstream und
// * Parameter an die Steuerfunktion abfrageSchleifePFBestimmungAusgabe
// * weiter, die die eigentliche Programmfunktionalitaet ausloest und
// * die Return-Codes liefert.
// * Im wesentlichen kuemmert sich main um die Aenderung von ostream fuer
// * unterschiedliche Ausgaben: neben cout (7. Moeglichkeit, und mit
// * Farbaenderungen auch 2.+3. Moeglichkeit) und Datei (1. Moeglichkeit)
// * waere auch in einen String denkbar, was hier eher stoeren wuerde,
// * zu Testzwecken aber praktisch ist ...:
// * ``std::ostringstream oss{};'', so dass dieser abgfragt werden kann:
// * ``if (oss.str() == "...") { ... }''.
int main (int argc, const char* argv[])
{ // Hauptfunktion mit Aufruf-Parametern
try // Absichern gegenueber Exceptions ...
{
std::string prgname = argv[0]; // Aufrufname des Programms
std::string frstParamStr = "";
bool frstParamUsed = 0; // neue bool an CLP: 1. Param. continue
int retStat = 0; // Fehlercode an OS/xterm/shell
// nach Parameter fragen bzgl. output - bool fileOut setzen!
if (argc > 1) // mindestens ein Parameter gegeben ...
frstParamStr = argv[1]; // String hat 1. Parameter oder ist leer
if ((frstParamStr == "-f") || (frstParamStr == "--file"))
{ // * 1. Moeglichkeit: Ausgabe in Datei
frstParamUsed = 1; // 1. Parameter wurde verwendet
/* Begruessung */ // Erst auf den Bildschirm ..
begruessung (std::cout, 1, prgname); // .. Begruessung
myOutputFilename = std::string("PrimZahlZerlegung_")+
getDatStr(std::cout)+std::string("_JMB.txt");
outputFilename = myOutputFilename;
meldeInfo (std::cout, 0, "Die wirkliche Ausgabe erfolgt nun ueber die Datei:");
meldeInfo (std::cout, 0, std::string(" * '")+outputFilename+std::string("'!"));
farbLos = true; // keine ANSI-Farben
std::ofstream datei {outputFilename};
// Datei outputFilename -^ wird neu erzeugt oder bei Existenz
// ueberschrieben (daher ggf. sinnvoller mit Zeitstempel im Namen);
// dass Oeffnen und Schliessen ueberlaesst man sicherheitshalber
// den Mechanismen von ofstream (Konstruktor und Destruktor) - AWG!
/* Begruessung */ // .. nun auch in die Datei
begruessung (datei, 1, prgname);
meldeInfo (datei, 0, std::string("Diese Ausgabe-Datei heisst: '")+outputFilename+std::string("'!"));
/* Hauptteil */
retStat = abfrageSchleifePFBestimmungAusgabe (datei, argc, argv, frstParamUsed);
if (anzFaktorZerlegungen == 1)
{ // Info, wenn Primfaktoren ueberhaupt berechnet werden sollten
meldeInfo (datei, 1, "Es konnte keine sinnvolle Eingabe gefunden werden");
}
/* Verabschiedung */ // erst in die Datei ..
begruessung (datei, 0, prgname); // Verabschiedung
farbLos = false; // nun wieder mit ANSI-Farben
if (anzFaktorZerlegungen == 1)
{ // Info, wenn Primfaktoren ueberhaupt berechnet werden sollten
meldeInfo (std::cout, 1, "Es konnte keine sinnvolle Eingabe gefunden werden");
}
/* Verabschiedung */ // nun auch auf den Bildschirm ..
begruessung (std::cout, 0, prgname); // Verabschiedung
} else if ((frstParamStr == "-m") || (frstParamStr == "--mono"))
{ // * 2. Moeglichkeit: monochromatische Darstellung - Default von xterm
frstParamUsed = 1; // 1. Parameter wurde verwendet
farbLos = true; // keine ANSI-Farben
/* Begruessung */ // Auf den Bildschirm ..
begruessung (std::cout, 1, prgname); // Begruessung monochrom
meldeInfo (std::cout, 0, "Die wirkliche Ausgabe erfolgt nun monochromatisch:");
/* Hauptteil */
retStat = abfrageSchleifePFBestimmungAusgabe (std::cout, argc, argv, frstParamUsed);
if (anzFaktorZerlegungen == 1)
{ // Info, wenn Primfaktoren ueberhaupt berechnet werden sollten
meldeInfo (std::cout, 1, "Es konnte keine sinnvolle Eingabe gefunden werden");
}
/* Verabschiedung */ // Auf den Bildschirm ..
begruessung (std::cout, 0, prgname); // Abschied monochrom
} else if ((frstParamStr == "-i") || (frstParamStr == "--inverse"))
{ // * 3. Moeglichkeit: inverse Darstellung (gelb auf schwarz - Tur.Pascal3)
frstParamUsed = 1; // 1. Parameter wurde verwendet
farbLos = true; // keine ANSI-Farben
std::cout << LYELLOW_BLACK << "\n";
/* Begruessung */ // Auf den Bildschirm ..
begruessung (std::cout, 1, prgname); // Begruessung invers
meldeInfo (std::cout, 0, "Die wirkliche Ausgabe erfolgt nun invers:");
/* Hauptteil */
retStat = abfrageSchleifePFBestimmungAusgabe (std::cout, argc, argv, frstParamUsed);
if (anzFaktorZerlegungen == 1)
{ // Info, wenn Primfaktoren ueberhaupt berechnet werden sollten
meldeInfo (std::cout, 1, "Es konnte keine sinnvolle Eingabe gefunden werden");
}
/* Verabschiedung */ // Auf den Bildschirm ..
begruessung (std::cout, 0, prgname); // Abschied invers
std::cout << RESET << std::endl;
} else if ((frstParamStr == "-h") || (frstParamStr == "--help"))
{ // * 4. Moeglichkeit: Hilfstext
frstParamUsed = 1; // 1. Parameter wurde verwendet
std::cout << CLRSCR; // Bildschirm loeschen
/* Begruessung */ // Auf den Bildschirm ..
begruessung (std::cout, 1, prgname); // Begruessung zur Hilfe
/* Hilfstext-Ausgabe */
ausgabeInfotext (std::cout, 1); // Hilfs-Text ausgeben
meldeInfo (std::cout, 0, "Ende Hilfs-Text.");
/* Verabschiedung */ // Auf den Bildschirm ..
begruessung (std::cout, 0, prgname); // Abschied von Hilfe
} else if ((frstParamStr == "-v") || (frstParamStr == "--version"))
{ // * 5. Moeglichkeit: Versionsinfo
frstParamUsed = 1; // 1. Parameter wurde verwendet
std::cout << CLRSCR; // Bildschirm loeschen
/* Begruessung */ // Auf den Bildschirm ..
begruessung (std::cout, 1, prgname); // Begruessung zum Versionstext
/* Versions-Ausgabe */
ausgabeInfotext (std::cout, 0); // Versions-Text ausgeben
meldeInfo (std::cout, 0, "Ende Versions-Text.");
/* Verabschiedung */ // Auf den Bildschirm ..
begruessung (std::cout, 0, prgname); // Abschied vom Versionstext
} else if ((frstParamStr == "-b") || (frstParamStr == "-vh") || (frstParamStr == "-hv"))
{ // * 6. Moeglichkeit: Versions- und Hilfs-Text
frstParamUsed = 1; // 1. Parameter wurde verwendet
std::cout << CLRSCR; // Bildschirm loeschen
/* Begruessung */ // Auf den Bildschirm ..
begruessung (std::cout, 1, prgname); // Begruessung zur vollen Info
/* Versions-Ausgabe */
ausgabeInfotext (std::cout, 0); // Versions-Text ausgeben
/* Hilfstext-Ausgabe */
ausgabeInfotext (std::cout, 1); // Hilfs-Text ausgeben
meldeInfo (std::cout, 0, "Ende Versions- und Hilfs-Text.");
/* Verabschiedung */ // Auf den Bildschirm ..
begruessung (std::cout, 0, prgname); // Abschied von vollen Info
} else
{ // * 7. Moeglichkeit: Bildschirm - Standard {= Default}, ohne Spezial-Par.
farbLos = false; // Abschluss auf cout mit ANSI-Farben
/* Begruessung */ // Auf den Bildschirm ..
begruessung (std::cout, 1, prgname); // Begruessung zum Standardprogramm
meldeInfo (std::cout, 0, "Die gesamte Ausgabe erfolgt auf dem Bildschirm ...");
/* Hauptteil */
retStat = abfrageSchleifePFBestimmungAusgabe (std::cout, argc, argv, frstParamUsed);
if (anzFaktorZerlegungen == 1)
{ // Info, wenn Primfaktoren ueberhaupt berechnet werden sollten
meldeInfo (std::cout, 1, "Es konnte keine sinnvolle Eingabe gefunden werden");
}
/* Verabschiedung */ // Auf den Bildschirm ..
begruessung (std::cout, 0, prgname); // Abschied vom Standardprogramm
}
return retStat; // Programm-Ende mit Fehlercode-Rueckgabe
} catch (...) // Ende des try-Blocks zur Ausnahme-Beh.
{ // Behandlung der Ausnahmebedingung ...
meldeInfo (std::cout, 1, "Das Programm fand eine seltsame Ausnahmebedingung in main");
if (anzFaktorZerlegungen == 1)
meldeInfo (std::cout, 1, "Es konnte keine sinnvolle Eingabe gefunden werden");
return 1;
}
meldeInfo (std::cout, 1, "Das Programm sollte nicht an diese Stelle gelangen");
} // Ende: int main (int argc, const char* argv[])
/******************************************************************************
* Das war's - ein erstes Hobby - C++ - Programm - nicht zu trivial ... :)) *
******************************************************************************
*/
System: [🔧PC‑Tech‑Info] |
Intel Core 2 Duo T6400@ 2,0 GHz ❹ Penryn bogomips: 3989,82 |
Pentium Dual-Core T4300@ 2,1 GHz Penryn bogomips: 4189,40 |
Intel Core i7-2600K@ 3,4 GHz ❸ Sandy Bridge bogomips: 6799,86 |
Intel Core i7-4770T@ 2,5 GHz ❷ Haswell bogomips: 4988,40 |
Intel Core i7-6700@ 3,4 GHz Skylake bogomips: 6816,00 |
AMD Ryzen 5 3600@ 3,6-4,2 GHz ❶ Zen2 & RDNA 1.0 bogomips: 7186,43 |
---|---|---|---|---|---|---|
real: | 35,339 s | 33,724 s | 25,132 s | 23,829 s | 17,259 s | 16,046 s |
user: | 35,288 s | 33,620 s | 25,107 s | 23,825 s | 17,255 s | 16,024 s |
sys: | 0,004 s | 0,008 s | 0,009 s | 0,005 s | 0,004 s | 0,000 s |
$ ls -al example_debug example
-rwxrwxr-x 1 jmb jmb 60464 Sep 7 15:14 example_debug
-rwxrwxr-x 1 jmb jmb 56616 Sep 7 15:14 example
# d.h. 60464 = 59,05 kB / 56616 = 55.29 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]=f59476f8f7efd2f9dc548143f262f53b1191c37e, for GNU/Linux 3.2.0, not stripped
$ strings example
# Ausgabe aller Zeichenketten (Strings) des Executables (viel: 649 Zeilen)
$ 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 Erste Fassung: | 30. | Juli | 2019 |
Letzte Änderung: | 23. | Mai | 2022 |