[C++] Snippets

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C++] Snippets

Beitrag 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.
Ohne Input kein Output.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Jonathan
Establishment
Beiträge: 2545
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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:

Code: Alles auswählen

//*		
	BlockA;
/*/
	BlockB;
//*/
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:

Code: Alles auswählen

//*		
	Block;
//*/
Die Idee dahinter ist natürlich jeweils, dass // in einem Block Kommentar ignoriert wird, und /* sowie */ in Zeilenkommentaren ignoriert werden.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Schrompf
Moderator
Beiträge: 5045
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Schrompf »

Hmm... erscheint mir sehr mühsam konstruiert für den gewünschten Zweck. warum kein #ifdef oder ein if( true oder false )?
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: [C++] Snippets

Beitrag 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.
Zuletzt geändert von Spiele Programmierer am 19.11.2014, 15:49, insgesamt 1-mal geändert.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

Das stimmt natürlich – jetzt bin ich beruhigt :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
mnemonix
Establishment
Beiträge: 101
Registriert: 09.04.2010, 20:38

Re: [C++] Snippets

Beitrag 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.
Zuletzt geändert von mnemonix am 12.12.2014, 15:18, insgesamt 3-mal geändert.
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: [C++] Snippets

Beitrag 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.
Benutzeravatar
mnemonix
Establishment
Beiträge: 101
Registriert: 09.04.2010, 20:38

Re: [C++] Snippets

Beitrag 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. ;)
Benutzeravatar
Jonathan
Establishment
Beiträge: 2545
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
xq
Establishment
Beiträge: 1589
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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*"
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: [C++] Snippets

Beitrag 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.
Benutzeravatar
xq
Establishment
Beiträge: 1589
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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 ;)
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
dot
Establishment
Beiträge: 1745
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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... ;)
Zuletzt geändert von dot am 14.12.2014, 19:55, insgesamt 1-mal geändert.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: [C++] Snippets

Beitrag 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.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
mnemonix
Establishment
Beiträge: 101
Registriert: 09.04.2010, 20:38

Re: [C++] Snippets

Beitrag 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;
...
Benutzeravatar
Jonathan
Establishment
Beiträge: 2545
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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).
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Sternmull
Establishment
Beiträge: 264
Registriert: 27.04.2007, 00:30
Echter Name: Til
Wohnort: Dresden

Re: [C++] Snippets

Beitrag 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.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2545
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Jonathan »

Ah, danke für die Tipps. Hat sich doch schon wieder gelohnt, das hier zu posten :)
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag 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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten