C++Guns – RoboBlog blogging the bot

07.02.2024

Analyse: Frozen Throne: Randgruppen TD2 Rapper Mod

Filed under: Allgemein — Thomas @ 22:02
TV Glozer Flying only
Name Kosten Dmg Range Type freeze splash dmg/gold Dmg Range Cooldown Type freeze splash dmg/gold
Ernie Berrt 10 16-26 950 Siege no no 2.3
Barbara Salesch 35 31-45 900 Chaos no no 1.08
Günter Jauch 80 51-81 850 Normal no yes 0.83 (2) 105-250 1400 0.3 Pirce no yes 2.2 (8.8)
GZSZ 155 146-224 950 Spells no no 1.2
Anime Guy 260 225-510 1100 Normal no yes 1.4 (3)
MTV VIVA 390 345-440 1050 Chaos no yes 1.0 (2.3)
Big Brother 800 770-1550 3000 Chaos YES no 1.45

Auslands Helden
Name

Kosten Dmg Range Type freeze splash
Tengu Man 10 34-46 1000 Pierce no no
Clown Man 35 96-138 600 Normal no no
Aqua Man 155 120-155 1200 Magic no no
Sword Man 265 256-286 500 Pierce no no
Astro Man 400 388-452 2000 Hero no no
Green Devil 750 801-900 3000 Chaos no yes

Aushilfs Helden Flying only
Name

Kosten Dmg Range Type freeze splash dmg/gold Dmg Range Cooldown Type freeze splash dmg/gold
Spring Man 10 10-14 650 Pierce no no 1.2 (2.4)
Splash Man 60 75-105 700 Magic no yes 1.5 (3) 1000-2000 1500 4.0 Pierce no yes
Freeze Man 150 147-149 750 Siege yes no
Shade Man 225 207-263 1000 Pierce no no
Turbo Man 500 510-600 1000 Hero no no
Ninja Mask 750 801-900 3000 Chaos no yes

Aushilfsnazi
Name

Kosten Dmg Range Type freeze splash
Skinhead 24 22-26 600 Siege no yes
Kämtner 65 48-54 300 Normal no no
Altnazi 100 91-115 350 Normal no no
Parzival 120 101-101 1200 Chaos no no
Faschismus 340 156-204 1100 Magic no yes
Bushido 550 472-516 550 Chaos no yes
Führer 870 951-1050 3000 Chaos no no

Dealer
Name Kosten Dmg Range Type freeze splash
Alkopopskonsument 15 17-21 650 Pierce no no
Kettenraucher 55 26-60 650 Siege no yes
LSD Ulli 125 70-115 800 Magic no no
Pornomann 165 169-197 1400 Normal no yes
Z 300 194-218 850 Siege no yes
Xtasy Dude 410 376-406 600 Pierce no yes
David Hasselhoff 850 901-1000 3000 Chaos no no

Gastarbeiter
Name Kosten Dmg Range Type freeze splash dmg/gold
Osteuropäer 5 7-13 550 Magic no no 2 (2.5)
Asiate 20 27-33 650 Pierce no no 1.5 (3.0)
Türke 65 65-85 700 Siege no yes 1.15
Araber 130 79-91 950 Spells no no 0.653
Italiener 175 107-163 950 Magic no no 0.771
Holländer 425 206-236 1000 Normal YES yes 0.52 (2.08)
Roberto Blanco 750 801-900 3000 Chaos no no

Haider, Alfons
Name Kosten Dmg Range Type freeze splash
Arschficker

10 14-18 1000 Magic no no
Priester

40 21-27 1400 Normal YES no
Lesbe

90 80-110 1500 Normal no no
Gayporn

135 78-150 450 Chaos no no
Ufer wechseln 200 111-125 1400 Normal no yes
Dirk Bach 350 301-400 1200 Pierce no yes
Ronaldo 750 801-900 3000 Chaos no no

Kapital Wessi
Name Kosten Dmg Range Type freeze splash
Polizist 25 17-21 800 Siege no yes
Kapitalist 70 43-49 300 Normal no no
Manager 110 86-110 300 Normal ?? no
CDU/CSU 150 131-131 1200 Chaos no no
Finanzhai
Otto Waalkes
Schröder

Nachwuchs Rapper
Name Kosten Dmg Range Type freeze splash dmg/gold
Möchtergern Rapper

10 15-19 1000 Pierce no no 1.7 (3.4)
Freestyler

50 27-33 900 Pierce no no 0.6 (1.2)
Fler

90 67-87 700 Spells no yes 0.856
Sido

120 63-90 500 Hero no no 0.667
Dendeman

200 155-200 600 Spells no yes 0.89
Bushido

550 472-516 550 Chaos no yes 0.9
Aggro Berlin

750 801-900 10000 Chaos no no

Ossi Arbeiter
Name Kosten Dmg Range Type freeze splash
Soldat

12 17-21 800 Pierce no no
Mitläufer

45 51-57 750 Pierce no no
Mauerwachturm

90 65-85 700 Siege no yes
SED Zentrale 140 104-116 700 Spells no no
Stasi Offizier 230 147-203 950 Magic no no
Erich Honecker 375 226-256 1000 Normal no yes
Karl Marx 750 801-900 3000 Chaos no no

Pro Gamer
Name Kosten Dmg Range Type freeze splash
Konsolennoob

10 11-12 800 Pierce no no
WoW Zocker

40 21-27 900 Magic no no
C&C Kaputti

85 64-80 600 Siege no yes
UT Bekloppter
W3 Zocker
Diablo Freak
CS Owner

700 751-850 3100 Chaos no no

Udo Jürgens
Name Kosten Dmg Range Type freeze splash
Pensionist 14 16-24 800 Pierce no no
Leprakranker 55 64-80 1400 Siege no yes
Coolman 135 110-130 1080 Magic no yes
Dauererektion 200 109-137 800 Chaos no no
aids kranker 265 236-266 950 Spells no no
Michael J Fox 450 356-410 800 Siege no yes
Mr T 800 801-900 3000 Chaos no no

01.01.2024

Analye: Frozen Throne Tower Defense Warcraft III

Filed under: Allgemein — Thomas @ 23:01

Flame
40 70 110 150 260
40-80 60-150 90-300 150-750 240-1800
800 1000 1200 1500 1800

Lightning
Geld 40 60 80 120 150
Schaden 80-160 120-300 175-525 230-800 340-1500
Reichweite 1300 1500 1750 2000 2300

Froizen

60 80 100 120 80
30-70 40-130 55 -265 80-460 135-1325
800 1000 1200 1500 1800


Fizz Tower

frozenthronefizztower

Bei Tower 5 bekommt man den meisten schaden pro Geld. Das ist erst mal nicht verwunderlich. Aber der ist teuer und man kann ihn sich nicht leisten. Stattdessen also viel Tower 1 2 oder 3 kaufen? Tower 4 ist Betrug, man bekommt weniger Schaden pro Geld als bei Tower 3. Der Tower 3 schneidet am besten ab. Also diese bauen wie Sand am Meer.


Canon Tower

frozenthronecanontower

Bei den Cannonball Towers gibt es keine Präferenz bezüglich Schaden pro Geld. Zwar gibt es bei Tower 2,3 und 4 weniger Schaden pro Geld, aber durch die Splash Damage Funktion gleicht sich das wieder aus. Tipp: Die Tower erst aufrüsten wenn nötig, damit mehr Geld für die Fizzfizz Tower übrig ist.


Flame Tower

frozenthroneflametower

Der Flame Tower ist schon in der ersten Ausbau Stufe mit 2 Schaden pro Geld so gut wie der Canon Tower in vollem Ausbau, aber natürlich nicht so start. Der Schaden pro Geld Ratio steigt ab Ausbau Stufe 4 und 5 sehr stark an. Allerdings sind diese sehr teuer, so dass man sie nur im fortgeschrittenen Spiel bauen kann und sollte.


Lightning Tower

frozenthronelighttower

Den Lightning Tower auszubauen lohnt nicht! Man bekommt immer weniger Schaden pro Geld. Natürlich steigt die Reichweite des Towers, aber da die Flieger in der Regel sehr schnell unterwegs sind, kann der Tower so oder so nicht oft schließen. Womöglich bringt es etwas, den Tower an eine Ecke zu stellen, wo die Flieger eine Kehrtwendung machen.


Reichweiten Vergleich

frozenthronetowerrange

Die Reichweite des Canonballtowers ist im Mittel grob 1.3 mal höher als die des Fizz Towes. Daher diesen Tower dort platzieren wo er lange gerade Stecken beschießen kann, ohne dass der Turm sich viel drehen muss.


Map Analyse von Azote Vil's TEAM TD v1.3 (99Lv)

Tower Kosten 10 15 20 30 40 = 115

Strategie: Die Gegner laufen im Waagrechten und zweiten senkrechten Teil in einer Linie, fast mittig näher zur Inneren Mauer hin. Mit Tower die Gegner aufhalten ist nicht nötig. Die Flieger sind das größte Problem.

Flying Levels: 10 14 16 18 26 27 31 44 45 46 64 68 69 70 71 73 74
Rekord: Level 72

Level Geld
start 50
1 50 + 20
2 55 + 20
3 +20
4 +20
5 +20
6 +20
7 +20
8 +20
9 +20
10 +20 5-6 tower nötig
11 +20
12 +20
13 +40 !
14 +40 9 tower nötig
15
16 +2 10 langen nicht
17
18 +2 12 langen nicht
19 +2
20 +2
21 +2
22 +2
23 +2
24 +2
25 +3
26 +3 18 langen nicht
27 +3 19 langen nicht
28 +3
29 +3
30 +3
31 +3 22 lange nicht
32 +3
33 +3
34 +3
35 +3-6
36 +4
37 +4-6
38 +30-35
39 +4
40 +4
41 +4
42 +4
43 +4
44 +4 44 langen nicht
45 +4 44 lange nicht
46 +25 fliege
47 +4
48 +4
49 +5
50 +5
51 +5
52 +5
53 +5
54 +5
55 +5
56 +5
57 +5
58 +5
59 +5
60 +6
61 +6
62 +6
63 +6
64 +6 74 alle
65 +6
66 +6
67 +6
68 +6 78 eioner durhc
69 +6 3 durch
70 +7 7 durch
71 +7 11 durch
72

08.12.2023

C++ Guns: Compiler kürzt Formel

Filed under: Allgemein — Thomas @ 13:12

compiler_kürzt_formel

24.07.2023

C++ Guns: DOS codepage 437 to UTF8

Filed under: Allgemein — Tags: , — Thomas @ 09:07

Wenn die üblichen Encodings wie UTF8, Latin1, ISO-8859-15 nicht funktionieren kann man CP437 versuchen. Das ist der Original-Zeichensatz des IBM-PC ab 1981. Dieser enthält Umlaute die in den üblicherweise eingestellten Encodings nicht angezeigt werden.

Hier mein erster Versuch CP437 nach UTF8 zu konvertieren. Die Sourcecode Datei und der Compiler und das ganze Betriebssystem ist selbstverständlich auf UTF8 eingestellt, sonst funktioniert es nicht.

std::string cp437toUTF8(std::string_view str) {
    std::string result;
    result.reserve(str.size());
    for(unsigned char c : str) {
        switch(c) {
        case 129: result.append("ü"); break;
        case 132: result.append("ä"); break;
        case 142: result.append("Ä"); break;
        case 148: result.append("ö"); break;
        case 153: result.append("Ö"); break;
        case 154: result.append("Ü"); break;
        case 225: result.append("ß"); break;
        default: result.push_back(c);
        }
    }

    return result;
}

[1] https://de.wikipedia.org/wiki/Codepage_437
[2] https://www.ascii-code.com/CP437

28.06.2023

Ganglia SSD Metrics

Filed under: Allgemein — Tags: — Thomas @ 14:06

GMETRIC="/usr/bin/gmetric -c /etc/ganglia/gmond.conf"
DEV=/dev/sda

temperature=$(sudo smartctl -A $DEV | grep Temperature_Celsius |  awk '{print $10}')
Reallocated_Sector_Ct=$(sudo smartctl -A $DEV | grep Reallocated_Sector_Ct |  awk '{print $10}')
Current_Pending_Sector=$(sudo smartctl -A $DEV | grep Current_Pending_Sector |  awk '{print $10}')
Offline_Uncorrectable=$(sudo smartctl -A $DEV | grep Offline_Uncorrectable |  awk '{print $10}')
UDMA_CRC_Error_Count=$(sudo smartctl -A $DEV | grep UDMA_CRC_Error_Count |  awk '{print $10}')
Program_Fail_Count_Chip=$(sudo smartctl -A $DEV | grep Program_Fail_Count_Chip |  awk '{print $10}')
Erase_Fail_Count_Chip=$(sudo smartctl -A $DEV | grep Erase_Fail_Count_Chip |  awk '{print $10}')
Wear_Leveling_Count=$(sudo smartctl -A $DEV | grep Wear_Leveling_Count  |  awk '{print $10}')
Used_Rsvd_Blk_Cnt_Chip=$(sudo smartctl -A $DEV | grep Used_Rsvd_Blk_Cnt_Chip  |  awk '{print $10}')
Program_Fail_Cnt_Total=$(sudo smartctl -A $DEV | grep Program_Fail_Cnt_Total  |  awk '{print $10}')
Erase_Fail_Count_Total=$(sudo smartctl -A $DEV | grep Erase_Fail_Count_Total  |  awk '{print $10}')

echo "temperature" $temperature
echo "Reallocated_Sector_Ct" $Reallocated_Sector_Ct
echo "Current_Pending_Sector" $Current_Pending_Sector
echo "Offline_Uncorrectable" $Offline_Uncorrectable
echo "UDMA_CRC_Error_Count" $UDMA_CRC_Error_Count
echo "Program_Fail_Count_Chip" $Program_Fail_Count_Chip
echo "Erase_Fail_Count_Chip" $Erase_Fail_Count_Chip
echo "Wear_Leveling_Count " $Wear_Leveling_Count 
echo "Used_Rsvd_Blk_Cnt_Chip" $Used_Rsvd_Blk_Cnt_Chip
echo "Program_Fail_Cnt_Total" $Program_Fail_Cnt_Total
echo "Erase_Fail_Count_Total" $Erase_Fail_Count_Total


$GMETRIC  -t float -n "Temperature" -u "Celcius" -g "SSD" -v $temperature
$GMETRIC  -t float -n "Reallocated_Sector_Ct" -g "SSD" -v $Reallocated_Sector_Ct
$GMETRIC  -t float -n "Current_Pending_Sector" -g "SSD" -v $Current_Pending_Sector
$GMETRIC  -t float -n "Offline_Uncorrectable" -g "SSD" -v $Offline_Uncorrectable
$GMETRIC  -t float -n "UDMA_CRC_Error_Count" -g "SSD" -v $UDMA_CRC_Error_Count
$GMETRIC  -t float -n "Program_Fail_Count_Chip" -g "SSD" -v $Program_Fail_Count_Chip
$GMETRIC  -t float -n "Erase_Fail_Count_Chip" -g "SSD" -v $Erase_Fail_Count_Chip
$GMETRIC  -t float -n "Wear_Leveling_Count" -g "SSD" -v $Wear_Leveling_Count
$GMETRIC  -t float -n "Used_Rsvd_Blk_Cnt_Chip" -g "SSD" -v $Used_Rsvd_Blk_Cnt_Chip
$GMETRIC  -t float -n "Program_Fail_Cnt_Total" -g "SSD" -v $Program_Fail_Cnt_Total
$GMETRIC  -t float -n "Erase_Fail_Count_Total" -g "SSD" -v $Erase_Fail_Count_Total

19.06.2023

C++ Guns: How to convert from UTC to local time in C++?

Filed under: Allgemein — Tags: — Thomas @ 11:06

Convert from a broken down date time structure from UTC to localtime in C++.

See Stackoverflow: How to convert from UTC to local time in C?
I converted the code from C to C++ and make it shorter.

// replace non std function strptime with std::get_time

#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime>

/*
  Convert from a broken down date time structure from UTC to localtime.
  See https://stackoverflow.com/questions/9076494/how-to-convert-from-utc-to-local-time-in-c
*/
std::tm UTC2localtime(std::tm tp) {
  // make sure Daylight saving time flag is not accidentally switched on in UTC time
  tp.tm_isdst = 0;

  // get seconds since EPOCH for this time
  const time_t utc = std::mktime(&tp);
  std::cout << "UTC date and time in seconds since EPOCH: " << utc << "\n";

  // convert UTC date and time (Jan. 1, 1970) to local date and time
  std::tm e0{};
  e0.tm_mday = 1;
  e0.tm_year = 70;

  // get time_t EPOCH value for e0. This handles daylight saving stuff.
  // The value is e.g. -3600 for 1h difference between the timezones
  const time_t diff = std::mktime(&e0);

  // calculate local time in seconds since EPOCH
  const time_t local = utc - diff;
  std::cout << "local date and time in seconds since EPOCH: " << local << "\n";

  // convert seconds since EPOCH for local time into local_tm time structure
  std::tm local_tm;
  if(localtime_r(&local, &local_tm) == nullptr) {
    throw std::system_error(errno, std::generic_category(), "UTC2localtime(): in conversion vom UTC to localtime");
  }
  return local_tm;
}

int main() {
  // hard coded date and time in UTC
  std::string datetime = "2013 11 30 23 30 26";
  std::cout << "UTC date and time to be converted in local time: " << datetime << "\n";

  // put values of datetime into time structure
  std::tm UTC_tm{};
  std::istringstream ss(datetime);
  ss >> std::get_time(&UTC_tm, "%Y %m %d %H %M %S");

  if(ss.fail()) {
    throw std::runtime_error("Can not parse datetime from datetime '" + datetime + "' to format %Y %m %d %H %M %S");
  }

  const std::tm local_tm = UTC2localtime(UTC_tm);
  std::cout << "local date and time: " << std::put_time(&local_tm, "%Y-%m-%d %H:%M:%S %Z") << "\n";
}

15.04.2023

AVR-GCC 15 für Linux installieren / compilieren

Filed under: Allgemein — Thomas @ 20:04

Es gibt bereits eine sehr gute Anleitung für das Installieren vom avr-gcc [1] [2] ..., aber sie sind veraltet. Ich werde im folgenden nur das beste von diesen Artikel übernehmen.

illustration

Zusammenfassung:

Der AVR 8-Bit RISC Mikrocontroller von Atmel ist ein sehr verbreiteter Mikrocontroller. Es ist nur ein Chip mit EEPROM, RAM, Analog zu Digital Umwandler, einer Menge digitaler Ein- und Ausgabezeilen, Timern, UART für RS 232 Kommunikation und vielen anderen Dingen.

Das beste ist jedoch, dass es dafür unter Linux eine vollständige Programmierumgebung gibt: Man kann diesen Mikrocontroller in C++ programmieren, mit dem GCC Compiler.

Die Anleitung ist in mehrere Teile gegliedert. Im ersten Teil wird die Installation erklärt. IM zweiten ein kleines Testprojekt. Im dritten wird gezeigt, wie man damit denn nun seine Programme für den AVR erstellt. Im vierten Teil stehen noch ein paar typische Fehlermeldungen und die Lösungen. Und im letzten ein paar weiterführende Links.

Fertige Pakete

Leider gibt es zu diesem Zeitpunkt (04.2023) keine aktuellen AVR GCC Pakete in den Repositories der Distributionen. Es führt also kein Weg am compilieren vorbei. Wenn die Repositories aktualisiert werden, werde ich das hier vermerken.
Ausnahme bildet das Paket avrdude, dass mit Version 6.3 (2016, Debian 11 bullseye) zwar auch schon etwas älter ist, aber dennoch wird es funktionieren. In der nächsten Debian Version, welche wahrscheinlich im Juni 2023 veröffentlicht wird, ist ein aktuelleres avrdude mit der Version 7.1 dabei. Auf er github Seite von avrdude [7] gibt es Informationen, wie man jetzt schon die neuste Version bekommt.

Avrdude lässt sich mit dem folgenden Befehl aus den Repositories installieren:

# apt-get install avrdude

Eure Voraussetzungen

Ihr müsst grundsätzliche Linux Kenntnisse mitbringen und den Willen sich durch die Anleitung durch zu beißen. Es kann an der ein oder andere Stelle Probleme geben, dann Ruhe bewahren und meist findet man die einfache Lösung schnell von selbst.

AVR GCC compilieren

Also los. Wir brauchen folgende Software:

binutils
binutils-2.44.tar.bz2
oder
binutils-2.44.tar.bz2

GCC
gcc-15.1.0.tar.gz

avr libc
avr-libc-2.2.1.tar.bz2

Um möglicherweise bestehende AVR GCC Installationen nicht zu überschreiben, werden die Programme nach ~/bin/avrgcc-15 installiert.

Software Voraussetzungen

Um einem Compiler zu compilieren ist Voraussetzung, dass schon ein Compiler installiert ist - logisch.
Welche Pakete dafür zu installieren sind, variiert etwas zwischen den unterschiedlichen Linux Distributionen. Aber für Debian basierte System ist es im wesentlichen das Paket build-essential sowie das Paket texinfo für binutils.


# apt-get install build-essential texinfo

binutils compilieren

Das binutils Paket enthält alle nötigen low-level Utilities, um Objektdateien zu bauen. Es beinhaltet einen AVR assembler (avr-as), Linker (avr-ld), library handling tools (avr-ranlib, avr-ar), Programme, zum Erzeugen von Objektdateien, die auf das EEPROM des Microcontrollers (avr-objcopy) geladen werden können, disassembler (avr-objdump) und utilities wie avr-strip und avr-size.

Und so wird's gemacht:

$ tar xjf binutils-2.44.tar.bz2
$ cd binutils-2.44
$ mkdir build
$ cd build
$ ../configure --target=avr --disable-nls --prefix $HOME/bin/avrgcc-15
$ make -j 2
$ make install

Die Kompilation dauert etwa ein bis zwei Minuten.

Die binutils ist nun in dem Verzeichnis $HOME/bin/avrgcc-15/ installiert. Um sie auch aufrufen zu können, muss das Verzeichnis der PATH Umgebungsvariable hinzugefügt werden. Dies geschieht mit folgenden Kommando:


$ export PATH=$HOME/bin/avrgcc-15/bin/:$PATH

Nun testen wir, ob auch alles klappt. Mit dem Programm 'witch' wird überprüft ob eines der binutils Programme, genauer gesagt das Programm avr-objcopy, erreichbar ist.


$ which -a avr-objcopy
/home/kater/bin/avrgcc-15/bin/avr-objcopy
/usr/bin/avr-objcopy

Da ich zwei Installationen des avr gcc habe, eine alte Systeminstallation mit dem GCC 5 und die neue mit dem GCC 15, werden bei mir zwei Zeilen ausgegeben. Wichtig ist, dass die neue Installation, also der Path /home/kater/bin/avrgcc-15/ ganz oben steht, denn dieser wird als erstes durchsucht.
Um das avrgcc Verzeichnis dauerhaft in der PATH Variablen zu seichern, tragt ihr die export Zeile an das Ende der .bashrc Datei ein, die sich im Homeverzeichnis befindet.

AVR GCC compilieren

avr-gcc ist unser eigentlicher Compiler. Diesen zu compilieren ist der aufwendigste Teil, da es am längsten dauert und beim Compilieren am meisten schief gehen kann.
Die für den GCC notwendigen Pakete wie gmp, mpfr, mpc und isl müssen nicht von Hand installiert werden. Dies kann durch das Skript contrib/download_prerequisites erledigt werden. Am besten führt ihr folgende Befehle Schritt für Schritt aus und achtet auf mögliche Fehlermeldungen die kommen könnten. Nicht einfach blind die Befehle copy&pasten!


$ tar xzf gcc-15.1.0.tar.gz
$ cd gcc-15.1.0/
$ ./contrib/download_prerequisites
$ mkdir build
$ cd build/
$ ../configure --target=avr --disable-nls --enable-languages=c,c++ --disable-libssp --with-double=64 --with-long-double=64 --prefix $HOME/bin/avrgcc-15/
$ make -j 2
$ make install

Das Kompilieren hat bei mir etwa 35 Minuten gedauert. Genug Zeit um gemütlich den nächsten Absatz zu lesen ;)

Die Optionen von configure bedeuten folgendes

  • --target=avr Wir wollen für die Zielplattform AVR compilieren -- logisch
  • --disable-nls Native Language Support (NLS) brauchen wir nicht. Es ist sinnvoller die Compiler Meldungen auf englisch zu googlen, dann bekommt man schneller die passende Antwort.
  • --enable-languages=c,c++ Unsere Zielsparache ist C++
  • --disable-libssp libraries for stack smashing protection - Ist sicher einen gute Sache, auch auf einem AVR bestimmt wertvoll, ich mus mal nachschauen warum das in den anderen Anleitungen deaktiviert wurde...
  • --prefix $HOME/bin/avrgcc-15/ Der Compiler soll in der Homeverzeichnis nach bin/avrgcc-15 installiert werden und nicht in die Systemverzeichnisse.
  • --with-double=64 --with-long-double=64 Den Floatingpoint Typ (long)double mit 64bit compilieren und nicht mit 32.
  • Der letzte Punkt bedarf etwas Erklärung. Wir alle wissen, dass (32/64bit) Gleitkommaberechnungen auf einem 8bit Controller nicht unbedingt die beste Idee ist, da dies sehr viele Instruktionen erzeugt und der Speicherplatz sehr beschränkt ist. Es ist technisch möglich, aber man will es in der Praxis vermeiden. Wahrscheinlich ist das der Grund, warum der double-precision Typ für AVR auch auf 32bit eingestellt ist, statt 64bit. Anders sieht das bei Berechnungen zur Kompilierzeit aus. Diese werden auf einem normalen Computer erledigt, der im Vergleich zum AVR unendlich viel Speicherplatz hat und auch millionenfach schneller ist. Seit C++11 mit constexpr können bequem in normalen Code Berechnungen zur Kompilierzeit ausgeführt werden, es ist kein Gefummelt mit Makros mehr nötig. Und die Möglichkeiten werden mit jeder neuen C++ Version stetig verbessert. Zum Beispiel gibt es in C++23 (GCC13) das Keyword "consteval" welches garantiert, dass eine Funktion nur zur Kompilierzeit ausgeführt wird. Genau das Richtige für Mikrocontroller! Es spricht also nichts dagegen Berechnungen, die zur Kompilierzeit ausgeführt werden, mit 64bit double zu berechnen.

    Hier ein Beispiel das Probleme mit 32bit double Typen aufzeigt: die UBRR Berechnung für den USART. Wie genau die Berechnung aussieht ist dabei egal, wichtig ist nur, dass die Eingangswerte, die CPU Frequenz (z.B 20000000Hz) und die Baudrate (z.B. 1000000), als 32bit integer vorliegen müssen, da die Zahlen für 16bit Typen zu groß sind. Nun kann eine 32bit Ganzzahl nicht verlustfrei in eine 32bit Gleitzahl konvertiert werden, was in einer Warnung (oder Fehler je nach Einstellung) resultiert. Für diesen Fall wissen wir, dass der Verlust an Ziffern kein Problem ist, da wir die möglichen CPU Frequenz und Baud Rate kennen, aber wenn nicht mal dieses eine Beispiel zu 100% mit 32bit double funktioniert, wie soll das erst mit komplizierten Berechnungen funktionieren?!

    Aus diesem Grund habe ich double, wie gewohnt, auf 64bit eingestellt. Wenn man auf dem AVR unbedingt Gleitkommaberechnugen braucht, kann man den Typ float nutzen und alles ist wie immer.

    So, nach diesen Gedanken sollte die Kompilation fertig sein :)

    Zum Abschluss starte ich den Compiler und lasse mir die Versionsnummer ausgeben


    $ avr-gcc --version
    avr-gcc (GCC) 15.1.0

    Weiter geht es mit der Installation der avr-libc

    avr-libc compilieren

    Die Compilation der avr-libc gestaltet sich ähnlich. Folgende Befehle sind auszuführen:


    $ tar xjf avr-libc-2.2.1.tar.bz2
    $ cd avr-libc-2.2.1/
    $ mkdir build
    $ cd build/
    $ ../configure --build=`./config.guess` --host=avr --prefix=$HOME/bin/avrgcc-15/
    $ make -j 2
    $ make install

    Die Kompilation dauert etwa drei Minuten.

    Danach ist die Installation komplett und wir können mit dem Beispiel Projekt weiter machen.

    Ein kleines Testprojekt

    Die Hardware

    Wir beginnen mit einer kleinen Testschaltung, die du dann später erweitern kannst. Unser Testprogramm, so wie es hier dargestellt ist, bringt einfach eine LED zum Blinken. Man kann fertige Experimentierboards nutzen oder sich eine kleine Schaltung selbst zusammen löten. Das Beispiel ist für den ATmega8 geschrieben, kann aber leicht auf andere Typen angepasst werden.

    Schaltplan und Pinbelegung

    Schaltplan und Pinbelegung

    Aufgebaute Schaltung

    Aufgebaute Schaltung

    Ein externer Kristall an dem Mikrocontroller ist für dieses Beispiel nicht notwendig, da der eingebaute Oszillator benutzt wird der von Werk aus auf 1MHz eingestellt ist.

    Die Software

    Ein guter Start für die Programmierung von Mikrocontroller ist das AVR-GCC Tutorial [6] und, natürlich, das Datenblatt des verwendeten Kontrolles.
    Viel besser als alle Theorie ist ein richtiges Beispiel. Wir schreiben ein kleines Programm, das unsere LED blinken lässt. Nicht sehr nützlich, aber sehr gut für den Anfang.
    Ihr könne es hier runterladen: avrblink10zip Das zip enthält den folgenden Quelltext und eine Makefile.

    /*
     * blink.cpp
     * ATmega8 mit 1 MHz
     * PORTB wird ueber ein Timer alle 0.263s ein- und ausgeschaltet. Das entspricht 3.81Hz
     *
     * Der Takt beträgt 1Mhz. Der Timer Prescaler ist auf 1024 eingestellt und ein 8 Bit Timer
     * läuft nach 256 Increments über. Also
     * 1000000Hz / 1024 / 256 = 3.81Hz
     */
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    // Overflow Interrupt Routine von Timer 0
    ISR(TIMER0_OVF_vect) {
      // PORTB inventieren
      PORTB =~ PORTB;
    }
    
    int main() {
      // PORTB als Ausgang schalten
      DDRB  = 0xFF;
      // Alle Ausgaenge auf 0 schalten
      PORTB = 0x00;
    
      // Prescaler von Timer0 auf 1024 stellen
      TCCR0 |= (1 << CS02) | (1 << CS00);
      // Timer 0 Overflow Interrupt aktivieren
      TIMSK  |= (1 << TOIE0);
    
      // Interrupts einschalten
      sei();
    
      // Endlosschleife. Hier ist kein weiterer Code nötig.
      // Das Ein und Ausschalten der LED geschiet in der Overflow Interrupt Routine
      for(;;);
    }
    

    Die reichlichen Kommentare im Quelltext kommentieren ihn hoffentlich ausreichend.
    Kommen wir zum Makefile. Ich hab es extra super super super einfach gehalten, da das Ziel dieses Artikel nicht ist, Makefiles zu schreiben, sondern schnell das Beispiel erfolgreich zu bestreiten.

    all:
            avr-g++ -O1 -Wall -Wextra -Wconversion blink.cpp -mmcu=atmega8 -o blink.elf
            avr-objcopy -O ihex blink.elf blink.hex
    
    load:
            avrdude -p m8 -c avr911 -P /dev/ttyUSB0 -U flash:w:blink.hex:i
    
    clean:
            rm -f *.o *.hex *.elf
    

    Das Makefile besteht aus drei Targets "all", "load" und "clean". Zum compiliere des Quelltest, zum hochladen auf den Mikrocontroller und zum entfernen der compilat Datein. Die Angabe des Mikrocontroller Typs "atmega8" geschiet direkt mit der Compiler Option "-mmcu" und nicht über eine extra Makefile Variable, um die Sache einfacher zu halten. Wenn das Projekt wächst kann das Makefile entsprechend erweitert werden. Achtet unbedingt achten, daß die Einrückungen im Makefile explizit durch TABs erfolgen und nicht durch Leerzeichen! Das ist nervig, aber das ist nunmal so...

    Die Optionen "-Wall -Wextra -Wconversion" schalten viele Warnings ein. Auch solche die Anzeigen wenn einen implizite conversion statt findet. Also z.B. 16bit auf 8bit Integer was auf einem 8Bit Mikrocontroller nicht unbedingt das ist, was man eigentlich programmieren wollte. So kann man viele Stellen finden die möglicherweise Fehler enthalten und potentiell ein paar Instrutionen sparen. Denn das Debuggen auf einem Mikrocontroller ist schwer bis garnicht möglich.

    Allgemeine Fehlermeldungen

    Fehlermeldungen sollten eigentlich keine vorkommen. Wenn doch, vergewissert euch, dass ihr euch genau an die Anleitung gehalten und nichts falsch abgeschrieben habt!

    Hier ein paar typische Fehlermeldungen und ihr Lösungen:

    Permission denied
    Ihr habt nicht die Rechte, um diesen Befehl auszuführen. In dieser Anleitung müssen nur die Befehle zum installieren mit apt-get als root (also mit su oder sudo) ausgeführt werden.

    programmer is not responding
    Es kann keine Verbindung zum Programmer aufgenommen werden: Defektes Kabel, Programmer an der falschen Schnittstelle angeschlossen (default: /dev/ttyS0 statt z.B. /dev/ttypUSB0), kein Strom am Programmer etc.

    Fehlermeldungen beim compilieren von AVR GCC

    /usr/bin/ld: .libs/hwasan.o: relocation R_X86_64_PC32 against undefined symbol `__ehdr_start' can not be used when making a shared object; recompile with -fPIC
    Uh... Ich habe etwas rumgefrage und gegoogelt und am wahrscheinlichsten ist es, dass das Linux einfach zu alt ist. Ich bekam den Fehler bei einem ubuntu 19.04.

    Links

    [1] https://rn-wissen.de/wiki/index.php/Avr-gcc_und_avrdude_installieren by Me 2006, GCC
    [2] https://web.archive.org/web/20080611141419/http://www.tldp.org:80/linuxfocus/English/November2004/article352.shtml Guido Socher 2008, GCC 3.4, Example with ATmega8 (Englisch)
    [3] http://www.linuxfocus.org/Deutsch/November2004/article352.shtml Selber Artikel in Deutsch
    [4] https://web.archive.org/web/20080611143624/http://www.tldp.org/linuxfocus/English/March2002/article231.shtml Guido Socher 2002, GCC 3.0, Example with AT90S4433 (Englisch)

    [5] http://roboblog.fatal-fury.de/?p=4076 GCC 8 compilieren
    [6] https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
    [7] https://github.com/avrdudes/avrdude/
    [8] https://gcc.gnu.org/install/

    09.04.2023

    Cleanup your messy backup

    Filed under: Allgemein — Thomas @ 13:04

    Cleanup your messy backup by hand could be fun! Kinda of. The goal is to remove duplicated files and organize the files into a new structure.
    First of all lets record the free disk space over time.
    Consider this script which collects the free space over time in a file:

    $ cat freespace.sh 
    date | tr  '\n' ' ' | tee -a freespace_overtime
    df -h . | tail -n 1 | tee -a freespace_overtime
    
    $ cat freespace_overtime 
    Sun 09 Apr 2023 08:24:59 AM CEST /dev/sdb1      1008G  779G  178G  82% /mnt
    

    Now lets try to find some things like local Qt and boost installations, check the downloads/ and opt/ folders, .Trash/ .wine build/ .hg .svg git .local .cache .mozilla .dropbox java .steam bin/ , linux- kernel source, other obsolete downloads and delete them. Also check for hidden directories and hidden files...


    Local Qt installation are usually in the folder "QtSDK" or "Qt-*". The -prune option tell find to stop the recursion when find a matching folder.

    find . -type d -iname "QtSDK*" -prune 
    ./backup/kater_12.01.2018/kater/QtSDK
    
    find . -type d -iname "Qt-*" -prune
    ./backup/kater_12.01.2018/kater/Qt-1.6.0
    
    find . -type d -iname "*.java*" -prune
    

    6GB good start


    Find boost installations

    $ find . -type d -iname "boost*" -prune 
    ./backup/kater_12.01.2018/kater/download/boost_1_64_0
    

    Almost 1GB for me.


    Usually there is a lot of stuff in the downloads folder which can be removed

    $ find . -type d -iname "*download*" -prune
    

    Cleaned up 14GB!


    More obsolete stuff in opt/ folders.

    find . -type d -iname "opt" -prune
    

    Only 1GB this time.


    Find trash bins.

    find . -type d -iname "*trash*" 
    ./.Trash-1000
    ./backup/backup_80GB_HDD/backup_festrechner_13.03.2012/kater/.local/share/Trash
    

    5GB Trash... Be aware don't delete your regular backup files. Because there is no other backup ;)


    Old wine folders can be interesting. ...

    find . -type d -iname ".wine" -prune
    

    But not this time.


    Finding old build folders result in a lot of false positives.

    $ find . -type d -iname "*build*" -prune
    

    2GB for me.


    Old Mercurial hidden folders. Delete them all!

    $ find . -type d -iname ".hg" -prune
    

    And old subversion folders too. Gosch I have over 200 of them

    find . -type d -iname ".svn" -prune |   xargs rm -fr
    

    Don't forget to delete the git folders too! They should be in the cloud anyway ;)

    find . -type d -iname ".git" -prune
    

    Wow 11GB. Guess I deleted some other things too XD


    Nicht wirklich was zu holen bei .local.

     find . -type d -iname ".local" -prune
    

    Immerhin 1GB bei .cache

    find . -type d -iname ".cache" -prune
    

    Nur 700MB. Weg damit. Wenn da was wichtiges gespeichert wäre, hätte man es an anderer Stelle nochmal gespeichert.

    find . -type d -iname ".mozilla" -prune
    

    Dropbox haha als sich "Cloud" anfing durchzusetzen.

     find . -type d -iname "*dropbox*" -prune
    

    Haha Java weine ich keiner Träne nach

    find . -type d -iname "*.java*" -prune
    

    Mit Steam ist das eigentlich so eine Sache, aber auf der anderen Seite kann man alles neu runterladen. Man hat es ja gekauft...

    find . -type d -iname "*.steam" -prune
    

    1.3GB!


    Unglaublich was sich so alles in bin/ Ordner versteckt.

    find . -type d -iname "bin" -prune
    

    Immerhin 6GB.


    Versteckte Ordner sind ja auch so einen Sache von denen man nichts weiß und ergo auch nicht braucht.

    $ find /mnt -type d -iname ".*" -prune
    

    Das waren auch ein paar GB...


    Und versteckte Dateien erst. Was sich da an Müll ansammelt

    $ find /mnt -type f -iname ".*" -prune
    

    Diese dummen autoerstellen thumbnail Dateien können auch weg.

    find . -iname "thumbs.db" -print0 | xargs -0 du -ch
    

    Nur 40MB aber Müll ist Müll.


    Beim erstellen von Half Life Maps entstanden früher jeden Menge Mülldatein beim compilieren. Diese haben die Endung p0 p1 p2 p3 prt pts wic lin max und können nach kurzer Sichtung alle gelöscht werden.

    find . -iname "*.p0" -print0 | xargs -0 du -ch
    find . -iname "*.p1" -print0 | xargs -0 du -ch
    find . -iname "*.p2" -print0 | xargs -0 du -ch
    find . -iname "*.p3" -print0 | xargs -0 du -ch
    find . -iname "*.prt" -print0 | xargs -0 du -ch
    find . -iname "*.pts" -print0 | xargs -0 du -ch
    find . -iname "*.wic" -print0 | xargs -0 du -ch
    find . -iname "*.lin" -print0 | xargs -0 du -ch
    find . -iname "*.max" -print0 | xargs -0 du -ch
    

    Bei den .prt Datein hat sich _EINE_ Datei aus NFSp reingemogelt die nicht gelöscht werden sollte.
    Kanpp 1k Datei und 62M.

    06.11.2022

    skip and hint brushwork in praxis

    Filed under: Allgemein — Thomas @ 20:11

    Hi All!

    I want to show you some skip and hint brushwork in praxis.

    First I'll show you an overview of the map. The big green dot is where I take the sceenshots in game. And the line of sigth is blocked by one of the walls of the small room.


    overview

    But If you enable r_speeds 1 and gl_wireframe 2 in game, you see in the next screenshot pretty much everything from the map is rendered. Although the small building (with the NULL texture on top) blocks line of sight. 1200 wpoly nd 5500 epolys are rendered.


    img1

    To understand this, we'll load vis portal into J.A.C.K. They are stored in the .prt file but first you have to edit the file, otherwise it wont load. Open the file with a simple text editor. Keep the first two lines, then remove every line till the first line with the round brackets. (The number of lines you have to delte is the first number in the file.) It should then look like this:


    img2

    Or use the tool fixprt. You can download it here https://gamebanana.com/tools/6786

    In the next image you see some vis portals in blue which I loaded into J.A.C.K via Menu - Mmap - Load Portal File. There are two vis leafs marked. One in yellow and one in magenta. The start point is in the yellow leaf which goes up to the ceiling. The reason why pretty much everything
    is visible from the startpoint is, because its visible from the yellow portal. It dosen't matter the position of the player.


    img3

    For better understanding I also make a screenshot in J.A.C.K form the opposide of the map where you can see the yellow leaf. As you can see in the next image.


    img4

    In the next immage the player position is in the magenta leaf, right in front of the wall. Now only the sourounding walls of the map itself are rendered (and the lights (func_detail) and some other stuff on the ground (func_illusionary)). The magenta vis leaf is as high as the small room with the NULL texture.


    img5

    How we can achieve this? We have to decrease the hight of the yellow leaf to the hight of the small room. We simply split the leaf with the hint texture. In the next image you can see the brush I made. One side with the skip texture and the other with the skip texture. The hint side face up while will2k suggest to face it down. I don't know if there is any technical reason for this. It shoudlnt be. I like to few my maps from top. So put the hint texture on top of the brush make it easyer to see it in J.A.C.K.


    img6

    After running the compiler and load in the new vis leafs file, the leafs are cutted at the height of the small room. I marked the leafs in magenta as you can see in the next image.


    img7

    I started the game and take a screenshot from the start positon of the player. It works! The wpolys drops from 1200 to 533 and the epolys from 5500 to 375. (56% and 93% saved. It was worth it!)


    img8

    ==============================

    Next I'll show you how vis portals/leafs are good to detect world brushes which are potential good for func_detail.

    Here I made a lamp hanging from the ceiling. I forgot to turn it into a func_detail and as a result, the vis portals/leafs are cutted according to the rotation of the brush. This really looks not right.


    img9

    After changing the light brush to func_detail, run compiler, load prt file, the vis leafs/portals look way better :) And of cource the number of vis leafs/portals decreates, which is good (usually).


    img10

    Thats all for today. Many Thanks to theBoss and bluesed for their patience and endlos tips :)

    Here are somegood links:

    twhl goldsource tutorials https://twhl.info/wiki/page/category%3AGoldsource_Tutorials

    from will2k
    A Systematic Approach to Level Design https://gamebanana.com/tuts/10747
    Planning To Win Sketching Your Level https://gamebanana.com/tuts/10980
    Winning your optimization battle against the source engine https://gamebanana.com/tuts/11178
    Optimization Testing in Source Engine https://gamebanana.com/tuts/11586

    the wall (german) https://thewall.hehoe.de/
    r_speeds und ihre Optimierung https://thewall.hehoe.de/artikel/r_speeds/r_speeds.html

    17.09.2022

    C++ Guns: throw and catch all standard exceptions for fun

    Filed under: Allgemein — Tags: — Thomas @ 19:09

    This example throw and catch all standard exceptions just for fun
    exception list from https://en.cppreference.com/w/cpp/error/exception
    sorted after C++ Standard

    searching a stack trace? look at https://en.cppreference.com/w/cpp/utility/basic_stacktrace

    /* This example throw and catch all standard exceptions just for fun
     * exception list from https://en.cppreference.com/w/cpp/error/exception
     * sorted after C++ Standard
     *
     * searching a stack trace? look at https://en.cppreference.com/w/cpp/utility/basic_stacktrace
     */
    
    #include <iostream>
    #include <exception>
    #include <future>
    #include <regex>
    #include <filesystem>
    #include <chrono>
    #include <any>
    #include <optional>
    #include <variant>
    //#include <format> // C++20. Not implemented in GCC 12
    // #include <expected> // C++23
    
    
    int nCatched = 0;
    
    template<typename T>
    void check(const T& ex, std::string_view exceptionType) {
      nCatched++;
      std::string_view what(ex.what());
      // only compare the first chars from what() message, we are not intereseting in stuff after the exception type
      if(what.substr(0,exceptionType.size()) != exceptionType) {
          std::cerr << exceptionType << " what(): " << ex.what() << "\n";
          std::cerr << "\nERROR: Not all exception derived from " << exceptionType << " catched...\n";
          ::exit(EXIT_FAILURE);
        }
    }
    
    int main() {
    
      bool finish = false;
      int nThrow = 0;
      while(not finish){
        try {
          switch(nThrow) {
            case  1: ++nThrow; throw std::exception();
            case  2: ++nThrow; throw std::logic_error("std::logic_error");
            case  3: ++nThrow; throw std::invalid_argument("std::invalid_argument");
            case  4: ++nThrow; throw std::domain_error("std::domain_error");
            case  5: ++nThrow; throw std::length_error("std::length_error");
            case  6: ++nThrow; throw std::out_of_range("std::out_of_range");
            case  7: ++nThrow; throw std::runtime_error("std::runtime_error");
            case  8: ++nThrow; throw std::range_error("std::range_error");
            case  9: ++nThrow; throw std::overflow_error("std::overflow_error");
            case 10: ++nThrow; throw std::underflow_error("std::underflow_error");
            case 11: ++nThrow; throw std::bad_typeid();
            case 12: ++nThrow; throw std::bad_alloc();
            case 13: ++nThrow; throw std::bad_exception();
            case 14: ++nThrow; throw std::regex_error(std::regex_constants::error_collate); // C++11
            case 15: ++nThrow; throw std::system_error(ENOENT, std::system_category(), "std::system_error"); // C++11
            case 16: ++nThrow; throw std::ios_base::failure("std::ios_base::failure"); // C++11
            case 17: ++nThrow; throw std::future_error(std::future_errc::broken_promise); // C++11
            case 18: ++nThrow; throw std::bad_weak_ptr(); // C++11
            case 19: ++nThrow; throw std::bad_function_call(); // C++11
            case 20: ++nThrow; throw std::bad_array_new_length(); // C++11
            case 21: ++nThrow; throw std::filesystem::filesystem_error("std::filesystem::filesystem_error", std::error_code(ENOENT, std::system_category())); // C++17
            case 22: ++nThrow; throw std::bad_any_cast(); // C++17
            case 23: ++nThrow; throw std::bad_optional_access(); // C++17
            case 24: ++nThrow; throw std::bad_variant_access(); // C++17
            // case 25: throw std::chrono::nonexistent_local_time(); // C++ 20. Not implemented in GCC 12
            // case 26: throw std::chrono::ambiguous_local_time(); // C++20. Not implemented in GCC 12
            // case 27: throw std::format_error(); // C++20. Not implemented in GCC 12
            // case 28: throw std::bad_expected_access(); // C++23
            // case 29: throw std::tx_exception(); TODO
            default: {
              finish = true;
            }
          }
        }
        catch(std::bad_variant_access& ex) {
          check(ex, "bad variant access");
        }
        catch(std::bad_exception& ex) {
          check(ex, "std::bad_exception");
        }
        catch(std::bad_array_new_length& ex) {
          check(ex, "std::bad_array_new_length");
        }
        catch(std::bad_alloc& ex) {
          check(ex, "std::bad_alloc");
        }
        catch(std::bad_function_call& ex) {
          check(ex, "bad_function_call");
        }
        catch(std::bad_weak_ptr& ex) {
          check(ex, "bad_weak_ptr");
        }
        catch(std::bad_optional_access& ex) {
          check(ex, "bad optional access");
        }
        catch(std::bad_any_cast& ex) {
          check(ex, "bad any_cast");
        }
        catch(std::bad_typeid& ex) {
          check(ex, "std::bad_typeid");
        }
        catch(std::filesystem::filesystem_error& ex) {
          check(ex, "filesystem error");
        }
        catch(std::ios_base::failure& ex) {
          check(ex, "std::ios_base::failure");
        }
        catch(std::system_error& ex) {
          check(ex, "std::system_error");
        }
        catch(std::regex_error& ex) {
          check(ex, "Invalid collating element in regular expression"); // regex_error.what does not print the exception type first...
        }
        catch(std::underflow_error& ex) {
          check(ex, "std::underflow_error");
        }
        catch(std::overflow_error& ex) {
          check(ex, "std::overflow_error");
        }
        catch(std::range_error& ex) {
          check(ex, "std::range_error");
        }
        catch(std::runtime_error& ex) {
          check(ex, "std::runtime_error");
        }
        catch(std::future_error& ex) {
          check(ex, "std::future_error");
        }
        catch(std::out_of_range& ex) {
          check(ex, "std::out_of_range");
        }
        catch(std::length_error& ex) {
          check(ex, "std::length_error");
        }
        catch(std::domain_error& ex) {
          check(ex, "std::domain_error");
        }
        catch(std::invalid_argument& ex) {
          check(ex, "std::invalid_argument");
        }
        catch(std::logic_error& ex) {
          check(ex, "std::logic_error");
        }
        catch(std::exception& ex) {
          check(ex, "std::exception");
        }
      } // while
    
    
      if(nThrow != nCatched) {
        std::cerr << nThrow << " exception thrown but " << nCatched << " catched\n";
      } else {
        std::cout << "All exceptions which was thrown was catched\n";
      }
    
      return EXIT_SUCCESS;
    }
    

    $ ./a.out
    All exceptions which was thrown was catched

    « Newer PostsOlder Posts »

    Powered by WordPress