32bit/64bit/...?



  • Badestrand schrieb:

    unskilled schrieb:

    sizeof wird doch erst zur Laufzeit ausgewertet - aber man brauch es ja zur Compilezeit schon...

    sizeof wird schon zur Laufzeit ausgewertet, ist aber nunmal kein Makro/Define. Falls es dir nur um size_t und ptrdiff_t geht:

    template<int PointerBytes>
    struct MainTypes;
    
    template<>
    struct MainTypes<4>
    {
    	typedef int          Signed;
    	typedef unsigned int Unsigned;
    };
    
    template<>
    struct MainTypes<8>
    {
    	typedef long long          Signed;
    	typedef unsigned long long Unsigned;
    };
    
    typedef MainTypes<sizeof(void*)>::Signed    ptrdiff_t;
    typedef MainTypes<sizeof(void*)>::Unsigned  size_t;
    

    jopp, nur darum geht es mir - danke - hätt ich der wegen auch ma drauf kommen können 😉

    bb



  • Badestrand schrieb:

    unskilled schrieb:

    sizeof wird doch erst zur Laufzeit ausgewertet - aber man brauch es ja zur Compilezeit schon...

    sizeof wird schon zur Laufzeit ausgewertet, [...]

    typedef MainTypes<sizeof(void*)>::Signed    ptrdiff_t;
    

    Möp. Was müssen Templateparameter sein? Richtig, Compilezeit-Konstanten. Und wann werden Compilezeit-Konstanten ausgewertet? Und am Schluss die Quizfrage: wenn der Compiler ein sizeof() als Templateparameter schluckt, wann wir das dann ausgewertet? (Und wann weiß ein Compiler die größe eines Datentyps?)



  • Badestrand schrieb:

    template<int PointerBytes>
    struct MainTypes;
    
    template<>
    struct MainTypes<4>
    {
    	typedef int          Signed;
    	typedef unsigned int Unsigned;
    };
    
    template<>
    struct MainTypes<8>
    {
    	typedef long long          Signed;
    	typedef unsigned long long Unsigned;
    };
    
    typedef MainTypes<sizeof(void*)>::Signed    ptrdiff_t;
    typedef MainTypes<sizeof(void*)>::Unsigned  size_t;
    

    Woher weißt Du denn, dass ein int 4 Bytes groß ist und long long 8 Bytes groß ist? Wenn int und char und void* alle 32 Bit besitzen, bekommst Du mit sizeof jeweils eine 1 heraus.

    Siehe stdint.h für vorgefertigts typedef s.

    Wenn man sich typedef s für intptr_t und uintptr_t selber basteln will, könnte man das mit TMP (template meta programming) machen. Man schreibe sich Typlisten für signed und unsigned Ganzzahlen und durchläuft diese bis man einen gefunden hat, der die gleiche Größe wie ein void* besitzt:

    struct nil {};
    
      template<typename Head, typename Tail>
      struct tl { typedef Head head; typedef Tail tail; };  
    
      typedef tl<signed char, tl<short, tl<int, tl<long,
              tl<long long, nil> > > > > signed_integers;
    
      typedef tl<unsigned char, tl<unsigned short, tl<unsigned, tl<unsigned long,
              tl<unsigned long long, nil> > > > > unsigned_integers;
    
      template<typename List, unsigned Size>
      struct select_first_by_size;
      // Implementierung bleibt dem Leser als Übung ueberlassen
    
      typedef select_first_by_size<
              signed_integers, sizeof(void*) >::type my_intptr_t;
    
      typedef select_first_by_size<
              unsigned_integers, sizeof(void*) >::type my_intptr_t;
    

    Gruß,
    SP


  • Administrator

    Sebastian Pizer schrieb:

    Woher weißt Du denn, dass ein int 4 Bytes groß ist und long long 8 Bytes groß ist?

    Sehr wahrscheinlich weil er davon ausgeht, dass ein "normaler" Compiler genutzt wird. GCC, Builder, MSVC, Comeau ...

    Sebastian Pizer schrieb:

    Wenn int und char und void* alle 32 Bit besitzen, bekommst Du mit sizeof jeweils eine 1 heraus.

    Nur könnte dann deine spezielle Maschine keine Bytes verarbeiten. Das wäre ein ziemlicher Sonderfall 😉

    Sebastian Pizer schrieb:

    Siehe stdint.h für vorgefertigts typedef s.

    Witzbold. Das ist ein C99 Header und somit nicht Standard C++. Oben bemängelst du, dass die Lösung nicht dem Standard entspricht und dann verstösst du gleich selber dagegen ... lol

    Sebastian Pizer schrieb:

    Wenn man sich typedef s für intptr_t und uintptr_t selber basteln will, könnte man das mit TMP (template meta programming) machen. Man schreibe sich Typlisten für signed und unsigned Ganzzahlen und durchläuft diese bis man einen gefunden hat, der die gleiche Größe wie ein void* besitzt:

    Und in diesem Code gleich nochmals. long long ist nicht enthalten im aktuellen C++ Standard 😉

    Naja, aber man könnte auch gleich Boost verwenden:
    http://www.boost.org/doc/libs/1_39_0/libs/integer/index.html

    Allerdings nützt das reichlich wenig, wenn du, wie du es vorhin angesprochen hast, nicht auf den Wert eines sizeof(void*) Ausdruck gehen kannst.

    Grüssli



  • Badestrand schrieb:

    unskilled schrieb:

    oder wie würdet ihr euch so etwas basteln, wenn ihr es selbst machen müsstet?

    Ich würde glaubich über sizeof(long) gehen. Müsste man nochmal nachschauen, aber afair ist das sowohl im MSVC als auch unter'm g++ 32/64 Bit breit, eben je nach Konfiguration.

    Nein. long, sowie auch int bleiben unter 64Bit Windows 32 Bit.
    http://msdn.microsoft.com/de-de/library/bb978906.aspx#_32-Bit und 64-Bit in Koexistenz

    Lediglich Zeiger, sowie LongLong sind 64, was ich auch sinnvoll finde, dass nicht alles gleich 64 Bit wird..



  • drakon schrieb:

    Lediglich Zeiger, sowie LongLong sind 64, was ich auch sinnvoll finde, dass nicht alles gleich 64 Bit wird..

    Wurde bloss aus Kompatibilitätsgründen so gemacht.
    "Richtiger" wäre IMO wenn zumindest long 64 Bit hätte.

    Und dann gleich noch "long long" mit 128 Bit, jau, was wäre das fein 🙂



  • hustbaer schrieb:

    drakon schrieb:

    Lediglich Zeiger, sowie LongLong sind 64, was ich auch sinnvoll finde, dass nicht alles gleich 64 Bit wird..

    Wurde bloss aus Kompatibilitätsgründen so gemacht.
    "Richtiger" wäre IMO wenn zumindest long 64 Bit hätte.

    Und dann gleich noch "long long" mit 128 Bit, jau, was wäre das fein 🙂

    Ich finde je schon das komisch zu lesen: DWORD64

    128 Bit, das wäre natürlich was.. :p - Ich bezweifle aber nicht, dass das früher, oder später noch kommt. Spätestens bei Windows 128Bit :p



  • DWORD64 is wirklich einer der grossen Geniestreiche von Mirkosoft 🙂
    Was kommt als nächstes, BYTE24? BOOL16? FLOAT80? DOUBLE32?
    Oder gleich WCHAR8 😃



  • hustbaer schrieb:

    DWORD64 is wirklich einer der grossen Geniestreiche von Mirkosoft 🙂
    Was kommt als nächstes, BYTE24? BOOL16? FLOAT80? DOUBLE32?
    Oder gleich WCHAR8 😃

    😃 😃 😃

    naja - klar ists nich ganz sauber - aber immerhin logisch ^^
    man hätte auch QWORD für quad wählen können oder DDWORD xD
    aber da ist DWORD64 scho ein klein wenig besser, meinst du nicht auch?! 😛

    bb



  • DDWORD

    Ich bin ja kein Franzose 😃
    Hätte das ganz klar QWORD genannt!

    Oder es einfach mit UINT64 gut sein lassen.



  • Dravere schrieb:

    Sebastian Pizer schrieb:

    Woher weißt Du denn, dass ein int 4 Bytes groß ist und long long 8 Bytes groß ist?

    Sehr wahrscheinlich weil er davon ausgeht, dass ein "normaler" Compiler genutzt wird. GCC, Builder, MSVC, Comeau ...

    Wie auch immer ... man sollte sich nicht auf die Größen verlassen. Ich würde sagen long long ist Quasi-Standard. Ohne long long hast Du eventuell keine Ganzzahl, die groß genug für einen Zeiger ist. All das, was ich vorgeschlagen habe, würde im schlimmsten Fall einfach nicht kompilieren. Falls es kompiliert, produziert das Programm wenigstens keinen Müll (keine "silent errors").

    Dravere schrieb:

    Sebastian Pizer schrieb:

    Wenn int und char und void* alle 32 Bit besitzen, bekommst Du mit sizeof jeweils eine 1 heraus.

    Nur könnte dann deine spezielle Maschine keine Bytes verarbeiten. Das wäre ein ziemlicher Sonderfall 😉

    Ein Rechner kann immer Bytes einzeln verarbeiten. Nur manchmal sind Bytes auch 16 oder 32 bit groß. Es hat keiner behauptet, dass es sich dabei um Octets handeln muss.

    Dravere schrieb:

    Sebastian Pizer schrieb:

    Siehe stdint.h für vorgefertigts typedef s.

    Witzbold. Das ist ein C99 Header und somit nicht Standard C++. Oben bemängelst du, dass die Lösung nicht dem Standard entspricht und dann verstösst du gleich selber dagegen ... lol

    Das war echt kein Scherz. Ich würde den Header als Quasi-Standard bezeichnen. Er wird auch in C++0x übernommen (mit einer zsätzlichen C++ Version namens <cstdint> ). Falls es einen sochen Header nicht geben sollte, kompiliert Dein Programm nicht. Falls sizeof(int)!=4 gilt, obwohl Du Dich darauf verläßt, hast Du einen "stillen Fehler". (kompiliert, aber Programm produziert Müll).

    Dravere schrieb:

    Sebastian Pizer schrieb:

    Wenn man sich typedef s für intptr_t und uintptr_t selber basteln will, könnte man das mit TMP (template meta programming) machen. Man schreibe sich Typlisten für signed und unsigned Ganzzahlen und durchläuft diese bis man einen gefunden hat, der die gleiche Größe wie ein void* besitzt:

    Und in diesem Code gleich nochmals. long long ist nicht enthalten im aktuellen C++ Standard 😉

    Ich bin mir dessen bewusst. Dankeschön.

    Dravere schrieb:

    Naja, aber man könnte auch gleich Boost verwenden:
    http://www.boost.org/doc/libs/1_39_0/libs/integer/index.html

    Kann man. Der Header bindet stdint.h (oder etwas vergleichbares) ein, sofern existent, und kümmert sich auch um die Fälle, in denen keine Implementierungsdetails in Headern verfügbar sind.

    Dravere schrieb:

    Allerdings nützt das reichlich wenig, wenn du, wie du es vorhin angesprochen hast, nicht auf den Wert eines sizeof(void*) Ausdruck gehen kannst.

    Wie bitte? Du brauchst doch nur auf Gleichheit der Größen überprüfen
    ( sizeof(element_aus_typ_liste)==sizeof(void*) ).

    Gruß,
    SP


  • Administrator

    @Sebastian Pizer,
    Also du darfst mit quasi Standard argumentieren, ich allerdings nicht? Interessant ...

    Sebastian Pizer schrieb:

    Dravere schrieb:

    Allerdings nützt das reichlich wenig, wenn du, wie du es vorhin angesprochen hast, nicht auf den Wert eines sizeof(void*) Ausdruck gehen kannst.

    Wie bitte? Du brauchst doch nur auf Gleichheit der Größen überprüfen
    ( sizeof(element_aus_typ_liste)==sizeof(void*) ).

    Das bringt dir allerdings nichts. Ich habe gerade nochmal im Standard gesucht und bin nicht fündig geworden. Vielleicht kannst du etwas dazu finden und mich korrigieren, aber mir ist nicht bekannt, dass sizeof(void*) eine Grösse zurückliefern muss, welche einem sizeof(X) entsprechen muss, wobei X ein fundamentaler Typ ist. Also sizeof(void*) dürfte theoretisch einen Wert von 16 zurückgegeben, während dein grösster fundamentaler Typ nur 8 ist.

    Grüssli



  • Dravere schrieb:

    @Sebastian Pizer,
    Also du darfst mit quasi Standard argumentieren, ich allerdings nicht?
    Interessant ...

    Ja, darf ich. 🙂
    Im Ernst: Der Unterschied ligt in der Kompilierbarkeit. Wenn es stdint.h nicht gibt, dann bekommst Du das Programm gar nicht erst erzeugt. Eine Annahme wie sizeof(int)==4 ist dem Compiler scheissegal. Wenn man Implementierungs-spezifische Details ausnutzt, dann sollte man dafür sorgen, dass das Programm wenigstens nicht kompiliert, wenn die Annahmen falsch sind. Außerdem ist stdint.h und long long seit 10 Jahren bei C99 dabei und ist schon seit einer ganzen Weile im C++0x Entwurf enthalten. Aktuelle Compiler, die beides können (C und C++), sollten diesen Header und long long anbieten. Ich habe aber ehrlich gesagt nicht den Überblick über Compiler, wie es mit der Unterstützung genau aussieht. Diese Typlisten-Trickserei hätte ich wahrscheinlich mit #ifdef s geklammert, dass long long nur dann auftaucht, wenn der Compiler das auch kann.

    Dravere schrieb:

    Sebastian Pizer schrieb:

    Wie bitte? Du brauchst doch nur auf Gleichheit der Größen überprüfen
    ( sizeof(element_aus_typ_liste)==sizeof(void*) ).

    Das bringt dir allerdings nichts. Ich habe gerade nochmal im Standard gesucht und bin nicht fündig geworden. Vielleicht kannst du etwas dazu finden und mich korrigieren, aber mir ist nicht bekannt, dass sizeof(void*) eine Grösse zurückliefern muss, welche einem sizeof(X) entsprechen muss, wobei X ein fundamentaler Typ ist.

    Ist void* ein fundamentaler Typ? 🙂 Du meinst X = Ganzzahltyp.

    Dravere schrieb:

    Also sizeof(void*) dürfte theoretisch einen Wert von 16 zurückgegeben, während dein grösster fundamentaler Typ nur 8 ist.

    Kann gut sein. In einem solchen Fall gäbe es zu dem Problem auch keine Lösung. Da kann ich aber nichts für, wenn die Voraussetzungen für eine existierende Lösung nicht gegeben sind. C99 sagt auch, dass die typedefs für uintptr_t und intptr_t optional sind. Ich habe schon von Rechnern gehört, bei denen Zeiger 48 bittig waren und alle anderen Ganzzahltypen höchstens 32 Bit besaßen.

    Gruß,
    SP


  • Administrator

    Sebastian Pizer schrieb:

    Ja, darf ich. 🙂
    Im Ernst: Der Unterschied ligt in der Kompilierbarkeit.

    Nicht wirklich:

    template<bool>
    struct StaticAssert;
    
    template<>
    struct StaticAssert<true> { };
    
    // ...
    
    StaticAssert<sizeof(int) == 4> assert;
    

    Finito, hier hast du deinen gewünschten Kompilerfehler.

    Sebastian Pizer schrieb:

    Ist void* ein fundamentaler Typ? 🙂 Du meinst X = Ganzzahltyp.

    Nein und Nein.
    void* ist ein Compound Type. Das sind alle Zeiger.
    X darf auch ein float oder double sein, auch wenn es nicht all zu viel Sinn macht.

    Sebastian Pizer schrieb:

    Kann gut sein. In einem solchen Fall gäbe es zu dem Problem auch keine Lösung. Da kann ich aber nichts für, wenn die Voraussetzungen für eine existierende Lösung nicht gegeben sind.

    Dagegen sage ich ja auch nichts. Ich sage nur, dass du an der Lösung von Badestrand kritisierst, dass sich diese nicht an den Standard hält, aber deine tut es genauso wenig.

    Grüssli



  • Dravere schrieb:

    Dagegen sage ich ja auch nichts. Ich sage nur, dass du an der Lösung von Badestrand kritisierst, dass sich diese nicht an den Standard hält, aber deine tut es genauso wenig.
    Grüssli

    So, wie ich das sehe, macht der Typlisten-Ansatz zwei Annahmen weniger, welche nicht vom C++ Standard garantiert werden -- nämlich sizeof(int)==4 und sizeof(long long)==8.

    Ich habe nie behauptet, dass "long long" Teil des C++ Standards ist. Die Nutzung von "long long" in diesem Fall ist ein Trade-Off. Entweder es gibt einen Kompilierfehler, weil "long long" nicht bekannt ist, oder es gibt einem Kompilierfehler, weil sizeof(T)<sizeof(void*) für alle anderen Ganzhaltypen T gilt und deswegen das Template-Metaprogramm fehlschlegt. Was ist das kleinere Übel? Ich weiss es nicht... Das wär mir aber auch ehrlichgesagt solange egal, bis das Programm woanders kompiliert werden soll. Dann kann man immernoch die Typlisten mit #ifdefs anpassen...

    Gruß,
    SP


Anmelden zum Antworten