Seite 2 von 2
Re: [C++] Snippets
Verfasst: 07.02.2014, 03:17
von BeRsErKeR
Sieht nicht so aus, dass es mit VS 2010 geht. Für C# ja, für C++ nein. Es wird absolut gar nichts an Kommentaren von IntelliSense angezeigt.
Re: [C++] Snippets
Verfasst: 19.05.2014, 14:28
von Krishty
CodingCat hat geschrieben:Zwei verallgemeinernde Schleifenmuster, die mir elegant erscheinen: […]
Ich ergänze ums entfernt verwandte
#define until(...) while(false == (__VA_ARGS__))
für sowas wie
do {
++i;
} until(i == 100);
… damit man auch dort nicht so viele Negationen unterbringen muss.
Re: [C++] Snippets
Verfasst: 19.11.2014, 12:59
von Jonathan
Netter kleiner Trick mit Kommentaren, an den ich mich spontan erinnert habe und dann ein paar Minuten brauchte um herauszufinden, wie genau das nochmal ging. Die Idee ist einfach, dass entweder Block A oder Block B ausgeführt wird:
Ersetzt man die obere Zeile durch
/* wird statt
BlockA BlockB auskommentiert. Man braucht also nur 1 Zeichen ändern, um zwischen beiden hin und her zu wechseln. Natürlich haben moderne IDE's für sowas allerhand Komfort-Features, aber das hier funktioniert halt immer. Möchte man das ganze zur für einen Block benutzen, lässt man den Mittelteil einfach weg:
Die Idee dahinter ist natürlich jeweils, dass
// in einem Block Kommentar ignoriert wird, und
/* sowie
*/ in Zeilenkommentaren ignoriert werden.
Re: [C++] Snippets
Verfasst: 19.11.2014, 13:32
von Schrompf
Hmm... erscheint mir sehr mühsam konstruiert für den gewünschten Zweck. warum kein #ifdef oder ein if( true oder false )?
Re: [C++] Snippets
Verfasst: 19.11.2014, 13:55
von Krishty
Auch nur ein Zeichen zu ändern:
#if 0
BlockA;
#else
BlockB;
#endif
Hier bei Microsoft kann man das sogar schachteln; ich weiß aber gerade nicht, ob der Standard das garantiert.
Re: [C++] Snippets
Verfasst: 19.11.2014, 15:01
von Spiele Programmierer
Natürlich garantiert das der Standard.
Sonst könnte man ja zum Beispiel keine Präprozessor-Ifs nutzen, wenn man Include-Guards nutzt. Ist aber auch generell sehr üblich.
Re: [C++] Snippets
Verfasst: 19.11.2014, 15:35
von Krishty
Das stimmt natürlich – jetzt bin ich beruhigt :)
Re: [C++] Snippets
Verfasst: 12.12.2014, 14:26
von mnemonix
Wenn man mal schnell eingebetteten GLSL Code in seiner Anwendung nutzen möchte und keine Lust hat ständig lästige Anführungszeichen zu pflegen, gibt es eine einfache Lösung:
Vorher:
Code: Alles auswählen
const char* glslCode =
"#version 420 core\n"
"void main() {"
" gl_Position = vec4(0.0, 0.0, 0.0, 1.0);"
"}";
Nachher:
Code: Alles auswählen
#define TO_STRING(x) #x
const char* glslCode = TO_STRING(
#version 420 core\n
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
}
);
Wichtig ist jedoch auch hier nach jedem GLSL-Präprozessor Statement einen Umbruch einzuführen, weil auch hier sonst alles in einer Zeile landet und es sonst zu einem Fehler führen würde.
EDIT:
Spiele Programmierer hat geschrieben:Es gibt eine einfachere Lösung.
C++11 Raw String Literal
Den Umbruch kannst du dir dann auch sparen und die Zeilenangaben stimmen noch.
Dank
Spiele Programmierer gibt es für VS2013 und C++11 Nutzer eine noch einfachere Lösung mithilfe von
Raw String Literals:
Code: Alles auswählen
const char* glslCode = R"glsl(
#version 420 core
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
}
)glsl";
Wichtig hierbei ist zu beachten, Anfang und Ende zu kennzeichnen. Sprich
R"Trennzeichensymbol(Zeichenkette)Trennzeichensymbol". Ich vermute das ist nötig um den Compiler nicht zu verwirren, weitere Anführungszeichen innerhalb der Zeichenkette könnten als Ende angesehen werden, und nicht als Teil der Zeichenkette.
Re: [C++] Snippets
Verfasst: 12.12.2014, 14:41
von Spiele Programmierer
Es gibt eine einfachere Lösung.
C++11 Raw String Literal
Den Umbruch kannst du dir dann auch sparen und die Zeilenangaben stimmen noch.
Re: [C++] Snippets
Verfasst: 12.12.2014, 14:58
von mnemonix
Cool, danke. Das ist natürlich eine noch viel bessere Lösung. Ich habe es oben zur Vollständigkeit hinzugefügt. Man lernt immer dazu. ;)
Re: [C++] Snippets
Verfasst: 13.12.2014, 23:01
von Jonathan
Ja, wirklich sehr ausgezeichnet. Ich hatte bisher immer so ein Webtool benutzt, dass aus mehrzeiligen Text einen C-String bastelt. War dann halt immer sehr nervig, es reinkopieren zu müssen. Ich bin froh, dass das nun ein Ende hat.
Re: [C++] Snippets
Verfasst: 14.12.2014, 14:24
von xq
Was imho noch fehlt (vorallem für die ganzen Buffergeschichten):
Code: Alles auswählen
#define OFFSET(type, member) (&(*(type*)nullptr).member)
liefert den Offset eines Members innerhalb eines Structs in "void*"
Re: [C++] Snippets
Verfasst: 14.12.2014, 18:34
von Spiele Programmierer
Auch das gibt es schon:
http://en.cppreference.com/w/cpp/types/offsetof
Das selbst zu implementieren basiert wohl streng genommen auf Undefined Behavior.
Re: [C++] Snippets
Verfasst: 14.12.2014, 19:01
von xq
Naja, wenn man die beiden mal vergleicht, wird man feststellen: ist genau das selbe. Aber gut zu wissen, dass es das schon fertig definiert gibt
Und nein, es basiert nicht auf undefined behaviour, sondern auf pointerarithmetik ;)
Re: [C++] Snippets
Verfasst: 14.12.2014, 19:30
von dot
Das Dereferenzieren eines Nullpointers ist definitiv UB und es ist nicht genau das selbe, denn offsetof() muss auch funktionieren, wenn der operator & irgendwie überladen wurde. Abgesehen davon funktioniert selbst offsetof() nur mit Standard Layout Structs... ;)
Re: [C++] Snippets
Verfasst: 14.12.2014, 19:51
von Krishty
Ich erinnere mich auch, dass in Valves Master-Header eine Erweiterung dieses Makros war, um ein Element in der übergeordneten struct zu finden.
struct Game {
struct World {
void draw() {
OUTER_MEMBER(world, Game, device)->BeginScene(); // this plus Differenz aus offsetof(Game::world), offsetof(Game::device) als decltype(Game::device)
…
}
} world;
D3DDevice * device;
};
Tausende Parameterübergaben haben sie erfolgreich gespart. Aber ich weiß bis heute nicht, wie ich dazu stehen soll :P
Re: [C++] Snippets
Verfasst: 14.12.2014, 20:56
von Spiele Programmierer
Naja, wenn man die beiden mal vergleicht, wird man feststellen: ist genau das selbe
Eher nicht. Bei einem großzügigen Compiler ist es eine schnelle und hässliche Möglichkeit das zu Implementieren.
Aber das ist nicht vom Standard so definiert. Da steht nämlich "Example Implemenation".
In Clangs Headern ist es zum Beispiel auf "__builtin_offsetof" definiert.
Re: [C++] Snippets
Verfasst: 11.02.2015, 01:39
von Krishty
Krishty hat geschrieben:Wo du es gerade erwähnst: Ich saß letztens an der Clang-Kompatibilität, bin aber nicht fertig geworden :( Für GCC und Clang sähe das Gegenstück so ähnlich wie das aus:
#define TODO_INTERNAL_DEFER(OPERAND, ...) OPERAND(__VA_ARGS__)
#define TODO(TODOTEXT) _Pragma(TODO_INTERNAL_DEFER(warning(TODOTEXT)))
Vielleicht kann, wer auf diesen Systemen entwickelt, was damit anfangen.
Ich habe jetzt hier aufgegeben:
#define STRINGIZE(X) #X
#define TODO(TODOTEXT) _Pragma(STRINGIZE(GCC warning "TODO: " #TODOTEXT))
Scheiß String-Gefrickel. Visual C++ macht es richtig.
Re: [C++] Snippets
Verfasst: 15.03.2015, 20:19
von mnemonix
Hier mal ein Code-Snippet zum Thema Code-Benchmarking nach
Intel. Habe ich gerade dazu verwendet um SSE Codespielereien zu benchmarken und es scheint ganz gut und stabil zu funktionieren. ^^ Die RDTSC* Befehle geben hierbei einen Timestamp nach Taktzyklen zurück. Der CPUID Befehl dient zum einen als Pipeline-Flush als auch als Befehlsbarriere bzgl. Reordering (so habe ich es zumindest verstanden). RDTSCP garantiert, dass alle vorherigen Befehle komplett abgearbeitet wurden, bevor der Timestamp gelesen wird. Die pushad und popad Befehle dienen zum Sichern und Wiederherstellen der Register (scheinen auf 64-Bit nicht mehr unterstützt zu werden, weil eine Sicherung hier wohl nicht mehr nötig ist, wegen der Fülle an Registern). Ich habe dazu auch mal versucht Intrinsics zu verwenden, nur fängt dann der Compiler an Instruktionen zu reordern, was für diesen Zweck wohl nicht erwünscht ist. Das Ganze lässt sich vielleicht auch noch erweitern, indem die Thread-Affinitäten und -Prioriäten noch angepasst werden (Stichwort: Context Switch).
Code: Alles auswählen
namespace benchmark
{
union Timestamp
{
std::uint64_t ui64;
struct
{
std::uint32_t ui64l;
std::uint32_t ui64h;
};
};
__forceinline std::uint64_t begin()
{
Timestamp timestamp;
__asm
{
pushad
xor eax, eax
cpuid
rdtsc
mov timestamp.ui64l, eax
mov timestamp.ui64h, edx
popad
}
return timestamp.ui64;
}
__forceinline std::uint64_t end()
{
Timestamp timestamp;
__asm
{
pushad
rdtscp
mov timestamp.ui64l, eax
mov timestamp.ui64h, edx
xor eax, eax
cpuid
popad
}
return timestamp.ui64;
}
}
// Anwendung
...
auto t0 = benchmark::begin();
// Code, der gebenchmarkt werden soll
auto t1 = benchmark::end();
auto dt = t1 - t0;
...
Re: [C++] Snippets
Verfasst: 27.07.2015, 14:35
von Jonathan
Ist streng genommen kaum ein C++ Snippet, sondern eine Kombination aus verschiedenen Dingen, könnte aber für einige hier ganz nützlich sein: Automatische Generierte Versionsinformationen
Angefangen hat alles damit, dass ich um kleine Dinge auszuprobieren vermehrt Branches in Git erstellt habe. Irgendwann wurde das aber unübersichtlich, wenn man z.B. noch eine fertig kompilierte Datei rumfliegen hatte, aber nicht mehr weiß, aus welchem Branch die jetzt kommt. Also wollte ich eine Dialogbox, die mir Infos über Git und den Kompilierzeitpunkt anzeigt. Das war mir dann sogar so viel wert, dass ich mich freiwillig wieder mit CMake beschäftigt habe. Ich habe mich dafür entschieden, möglichst wenig in CMake tun zu müssen, also wird die Hauptarbeit von einem kleinen Python-Skript erledigt, das alle Informationen sammelt und eine cpp Datei daraus generiert. Es hat ein bisschen gedauert, bis ich die Abhängigkeiten richtig konfiguriert habe (die VersionInfo.cpp soll immer dann neu generiert werden, wenn das Programm neu kompiliert wird, aber bloß nicht immer wenn man auf Ausführen klickt, weil man sonst nie starten kann, ohne neu zu linken), aber jetzt bin ich ganz zufrieden mit meiner Lösung.
Die CMake Datei:
Code: Alles auswählen
# hier einfach alles sammeln, was man bei ADD_EXECUTABLE angeben würde:
SET(SOURCE_FILES
${MAIN_FILES}
${MAIN_FILES}
${UI_FILES}
${MISC_FILES}
...
)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.cpp
COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/GenerateVersionInfo.py ${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.cpp
DEPENDS ${SOURCE_FILES}
)
ADD_EXECUTABLE(MeinProject ${SOURCE_FILES} ${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.cpp
)
Die VersionInfo.hpp (einfach dort im Programm inkludieren, wo man die Infos verarbeiten möchte)
Code: Alles auswählen
#pragma once
#include <string>
namespace VersionInfo
{
extern const std::string CompileTime;
extern const std::string CompileDate;
extern const std::string GitBranch;
extern const std::string GitCommit;
extern const std::string GitCommitDate;
extern const std::string GitCommitAuthor;
}
Das Python Script um die VersionInfo.cpp zu generieren:
Code: Alles auswählen
import sys
import datetime
import subprocess
import re
print("Generating ", sys.argv[1])
# Fetch information:
now = datetime.datetime.now()
time_string = now.strftime("%H:%M:%S")
date_string = now.strftime("%A, %d. %m. %Y")
git_branch = subprocess.check_output(["git", "branch", "--all"]).decode("utf-8")
git_commit = subprocess.check_output(["git", "log", "-n 1"]).decode("utf-8")
branch_string = re.search(r"\* *(.*)\n", git_branch).group(1)
commit_string = re.search(r"commit *(.*)\n", git_commit).group(1)
commitDate_string = re.search(r"Date: *(.*)\n", git_commit).group(1)
commitAuthor_string = re.search(r"Author: *(.*)\n", git_commit).group(1)
# Generate an info file:
with open(sys.argv[1], "w") as file:
file.write(
"""#include "VersionInfo.hpp"
namespace VersionInfo
{
""")
file.write(' const std::string CompileTime = "'+time_string+'";\n')
file.write(' const std::string CompileDate = "'+date_string+'";\n')
file.write(' const std::string GitBranch = "'+branch_string+'";\n')
file.write(' const std::string GitCommit = "'+commit_string+'";\n')
file.write(' const std::string GitCommitDate = "'+commitDate_string+'";\n')
file.write(' const std::string GitCommitAuthor = "'+commitAuthor_string+'";\n')
file.write("}\n")
Das ganze kann man dann ganz nach belieben anpassen und bei Bedarf weitere Informationen hinzufügen (z.B. auf welchem Gerät das Programm kompiliert wurde oder so).
Re: [C++] Snippets
Verfasst: 27.07.2015, 15:07
von Sternmull
So etwas in der Art nutze ich auch. Die Informationen zum aktuellen Zustand der Working-Copy lassen sich mit "git describe --dirty --always --abbrev=40" etwas einfacher ermitteln. Auf Branch-Namen lege ich dabei keinen großen Wert da die ja in der nächsten Minute schon wieder ganz anders aussehen können. Viel wichtiger ist das man weiß aus welchem Commit etwas gebaut wurde (egal ob der sich zukünftig in einem Branch befindet von dem man noch nichts wissen kann), und ob es lokale Änderungen gab die nicht in dem Commit enthalten sind (deshalb --dirty).
Für das Zusammenbauen des Strings ist übrigens
String-Formatierung äußerst komfortabel. Um Strings mit vielen Ersetzungen zu erzeugen mache ich oft so was:
Code: Alles auswählen
x = 123
y = 'hallo'
s = '''
int foo()
{{
x = {x}; y = "{y}";
}}
'''.format(**locals())
Das **locals() übergibt alle lokalen Variablen als Schlüsselwort-Argumente an die Formatierung. So stehen einem im Format-String alle Variablen zur Verfügung. Innerhalb einer sicherheitskritischen Web-Anwendung sollte man damit zwar vorsichtig sein, aber für so was wie deine Anwendung finde ich es sehr nützlich.
Re: [C++] Snippets
Verfasst: 27.07.2015, 16:32
von Jonathan
Ah, danke für die Tipps. Hat sich doch schon wieder gelohnt, das hier zu posten :)
Re: [C++] Snippets
Verfasst: 16.08.2018, 20:14
von Krishty
Gleichverteilte zufällige floats:
float rand_snorm_float(uint32 const r) {
return float(int(r) / 256) / 8388608.0f;
}
Hintergrund:
- erzeugt Zahlen im Bereich [-1, +0.999999881]
- float hat 23-Bit-Mantissen und kann damit alle Ganzzahlen im Bereich [-8.388.608, +8.388.608] ohne Verlust darstellen
- solche Ganzzahlen erzeugen wir durch arithmetischen Shift einer 32-Bit-Zufallszahl (acht statt neun Bits weil wir das höchstwertige Bit als Vorzeichen verwenden wollen)
- ganz nebenbei ist int -> float auf x86 schneller als unsigned int -> float
- der Shift ist einem Modulo vorzuziehen, weil die meisten Zufallszahlengeneratoren geringe Entropie in den niederwertigen Bits haben und wir lieber die höchstwertigen behalten wollen
- die Division durch 8.388.608 wird zur Multiplikation mit dem Reziprokwert optimiert, weil es eine glatte Zweierpotenz ist
- lässt sich perfekt via SIMD parallelisieren
- bloß nicht diese Methode verwenden – bei ihr sind durch die finale Subtraktion die unteren Bits immer Null!
- die xoroshiro-Methode erzeugt leider keine vorzeichenbehafteten Zahlen, das ist für 3D-Grafik schwach
- bloß nicht das Vorzeichen nachträglich draufkleistern – weil IEEE754 zwischen +0 und -0 unterscheidet, kommen Nullen bei euch am Ende doppelt so häufig vor wie andere Werte; dann lieber die -1 in meinem Code explizit rausschmeißen (damit der Bereich [-0.999999881, +0.999999881] wird)
Re: [C++] Snippets
Verfasst: 16.08.2018, 20:24
von Krishty
NaN-korrektes Clamping mit SSE:
NaN Poisoning Attacks gegen anderer Leute Code sind immer wieder lustig. Die meisten Leute machen ihr
clamp() falsch – und sind überrascht, dass
clamp(0.0f, x, 1.0f) nicht nur Zahlen zwischen
0 und
1 liefert.
Dabei gibt es auf x86 eine Besonderheit, die das ganze enorm vereinfacht:
MINPS und
MAXPS mit einem NaN-Parameter geben nämlich immer den zweiten Parameter zurück. Zum Verständnis:
_mm_min_ps(1.0f, 2.0f) →
1.0f
_mm_min_ps(1.0f, NaN) →
NaN
_mm_min_ps( NaN, 1.0f) →
1.0f
_mm_min_ps( NaN, NaN) →
NaN
MAXPS funktioniert genauso. Durch die Reihenfolge der Operanden können wir das Ganze also so formulieren, dass
clamp() niemals
NaN durchreicht:
__m128 clampNum(__m128 min, __m128 x, __m128 max) {
return _mm_min_ps(_mm_max_ps(x, max), min);
}
… und schon sind keine NaNs mehr möglich. Ein Angriffsvektor weniger, bzw. ein Dutzend Befehle weniger, falls ihr bisher explizit prüfen musstet.
Der Name ist übrigens nicht zufällig gewählt:
IEEE754-2008 schreibt vor, dass NaN-sichere
min()- und
max()-Versionen
minNum() und
maxNum() heißen. Leider ist x86 nicht kompatibel.