2016-07-26 28 views
2

Meine App enthält zahlreiche IDs. Ich möchte schließlich den Code für andere sichtbar machen, aber es den Reverse-Engineern der Laufzeitumgebung nicht leicht machen, nach leicht bekannten IDs zu suchen. Außerdem ist es während der Entwicklung hilfreich, in den Protokolldateien konstante IDs zu haben, um das Debuggen zu erleichtern. Aber zur Laufzeit möchte ich diese IDs zufällig machen, indem ich sie während der Release-Kompilierung erzeuge. Vorgeschlagener Code, der die <random> Lib verwendet, kann in GetRandomId1() unten gesehen werden. constexpr ermöglicht ihre Verwendung im Code wie in Switch-Anweisungen. Allerdings habe ich Probleme mit constexpr in meiner vorgeschlagenen Funktion, weil <random> nicht constexpr kompatibel ist. Gibt es eine andere Möglichkeit, Zufallszahlen zur Kompilierzeit zu generieren? Oder generiert Zufallszahlen zur Kompilierzeit, um sie zur Laufzeit als Konstanten zu verwenden, die gegen das Konzept constexpr behandelt werden?Ersetzen von magischen ID-Nummern durch zufällige IDs, die zur Kompilierungszeit generiert wurden

#include <iostream> 
#include <random> 

// this is the code I would like to use to generate a random number at compile time 
/*constexpr */int GetRandomId1() 
{ 
    std::random_device rd; // non-deterministic seed 
    std::mt19937 gen(rd()); // with constexpr uncommented: 
    // error C3250: 'rd': declaration is not allowed in 'constexpr' function body 
    // error C3249: illegal statement or sub-expression for 'constexpr' function 
    // error C3250: 'gen': declaration is not allowed in 'constexpr' function body 

    std::uniform_int_distribution<> distri(1000, 9999); // with constexpr uncommented: 
    // error C3250: 'distri': declaration is not allowed in 'constexpr' function bod 
    // error C3249: illegal statement or sub-expression for 'constexpr' function 
    // error C2134: 'std::uniform_int<_Ty>::operator()': call does not result in a constant expression 

    return distri(gen); 
} 

// this code is what works so far 
constexpr int GetRandomId2() 
{ 
    return 22; // how to make somewhat random? 
} 

constexpr int AAA = 10; 
//constexpr int AAA = GetRandonId1(); // error: is not constexpr function 
constexpr int BBB = GetRandomId2(); // ok 

void Func1(long ab) 
{ 
    switch(ab) 
    { 
    case AAA: 
     std::cout << AAA << std::endl; 
     break; 

    case BBB: 
     std::cout << BBB << std::endl; 
     break; 
    } 
} 

int main() 
{ 
    Func1(22); // ok: prints 22 

    return 0; 
} 

ich für eine gerade nach vorne suchen, wartbare Lösung, wie ich sie vorgeschlagen und im Gegensatz zu den starken Gebrauch von Vorlagen wie in How can I generate dense unique type IDs at compile time? vorgeschlagen. Auch in diesem Beitrag verweist @jmihalicza auf die Random number generator for C++ template metaprograms Forschungsarbeit. Dieses Papier beschreibt die Generierung von Zufallszahlen für die Kompilierungszeit unter Verwendung der Template-Metaprogrammierung, die ein komplizierter Versuch ist, der eine Aufgabe erfüllt, für die IMO constexpr entworfen wurde (zu wagen oder zu sagen?).

Aus Gründen der App-Architektur muss ich mir keine Gedanken über ID-Kollisionen machen, deshalb ist das kein Problem. Der App-Code würde sicherstellen, dass keine Duplikate zurückgegeben werden.

+6

Sie könnten immer einen benutzerdefinierten Pre-Build-Schritt hinzufügen, der Zufallszahlen in Datei erzeugt, um '# include'd zu sein – sp2danny

Antwort

4

Ich gab eine constexpr Zufallsgenerator here vor einiger Zeit, für einen verwandten Zweck constexpr String-Verschlüsselung, um gegen die gleichen Gegner zu helfen, die Sie betroffen sind.

Ich denke, es ist von vergleichbarer kryptographischer Sicherheit zu mt19937, die (ein sehr aufwendiger) linearer Rückkopplungsgenerator ist und sowieso nicht kryptografisch sicher ist.

Die Idee in diesem Code ist, __TIME__ und __LINE__ als Seed zum Generator zu verwenden.

typedef uint32_t u32; 
typedef uint64_t u64; 
typedef unsigned char uchar; 

template<u32 S, u32 A = 16807UL, u32 C = 0UL, u32 M = (1UL<<31)-1> 
struct LinearGenerator { 
    static const u32 state = ((u64)S * A + C) % M; 
    static const u32 value = state; 
    typedef LinearGenerator<state> next; 
    struct Split { // Leapfrog 
     typedef LinearGenerator< state, A*A, 0, M> Gen1; 
     typedef LinearGenerator<next::state, A*A, 0, M> Gen2; 
    }; 
}; 

// Metafunction to get a particular index from generator 
template<u32 S, std::size_t index> 
struct Generate { 
static const uchar value = Generate<LinearGenerator<S>::state, index - 1>::value; 
}; 

template<u32 S> 
struct Generate<S, 0> { 
    static const uchar value = static_cast<uchar> (LinearGenerator<S>::value); 
}; 


// Seed 

#define RNG_SEED ((__TIME__[7] - '0') * 1 + (__TIME__[6] - '0') * 10 + \ 
       (__TIME__[4] - '0') * 60 + (__TIME__[3] - '0') * 600 + \ 
       (__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000) + \ 
       (__LINE__ * 100000) 

Ich versuchte nicht, diese mit constexpr anstelle von Vorlagen neu zu schreiben, aber ich denke, TBH in C++ 11-Standard constexpr Funktionen für überhaupt etwas zu kompliziert nicht wesentlich schöner als Vorlagen ist. Es wird nur wirklich in C++ 14 Standard schön, wenn Sie tatsächlich lokale Variablen und so weiter haben können.

Trotzdem sollte es immer noch nicht so schwer sein, diese Generator-Implementierung ist nicht so schlimm.

Sie müssen auf jeden Fall Träume von std::random_device zur Kompilierzeit zu sprechen aufgeben. IIRC, in libc++ Implementierung, das ist im Grunde eine dünne Verpackung über std::fopen("/dev/urandom"). Ich kenne keinen C++ - Standard oder Vorschlag, der Dateisystemoperationen innerhalb von constexpr Berechnungen erlauben würde. :)

+0

Was bedeutet es," kryptographisch sicher "zu werden? Warum ist das zur Kompilierzeit nötig? Ist das der Grundgedanke hinter dem "Constexpr"? Zu meiner Art zu denken, da der Programmierer den Code im Rahmen einer bestimmten "conexpr" -Funktion steuert, sollte er derjenige sein, der entscheidet, was für den Rest des Programms als "const" behandelt werden soll. Die Entscheidung ist nicht größer als bei der Kompilierungszeit zu entscheiden, ob eine Mitgliedsvariable öffentlich, privat oder geschützt ist. – rtischer8277

+0

Die Frage ist, welche Art von Code sollte der Compiler ausführen können, um den 'constexpr'-Literaltyp zu erzeugen? Soll es wie für Ihre Metaprogrammierung nur header-only sein? Verpasst den Punkt von "constexpr". Sollte es auf externen Dateicode verwiesen werden? Verpasst den Punkt auch. – rtischer8277

+0

Ich glaube, Sie haben einige Missverständnisse darüber, was "constexpr" ist. "constexpr" ist nicht dasselbe wie "const", es hat wirklich nichts mit 'public, private' usw. zu tun. Es hat auch nichts damit zu tun, Compiler-Optimierungen zu aktivieren - wenn der Compiler einen Ausdruck beim Kompilieren berechnen kann Zeit ist es bereits frei, es unter der als-ob-Regel zu optimieren. Der wichtigste Vorteil von constexpr besteht darin, dass literale Typen als Vorlagenparameter verwendet werden können. –