static_cast<int>() vs short



  • Es ist langsam im Zugriff.



  • Es bringt nichts ein unsigned short (normal 2byte) zu nehmen, da es vom Compiler eh auf 4byte vergrößert wird. Also kannste auch gleich unsigned int oder unsigned long nehmen bzw. noch besser isses imho std::size_t zu nehmen.



  • In welchem Header ist das eigentlich definiert? Mein Compiler schluckt auch size_t (ohne std und ohne Includes)?!



  • Soweit ich weiss ist size_t inzwischen auch Bestandteil der Sprache und z.B. der Typ den sizeof() zurückgibt - damit werden wohl dann auch keine Header mehr gebraucht...

    (Dass size_t sich im Namespace std befindet war mir btw auch neu)



  • rofl size_t
    nimm int


  • Mod

    soweit es pc-technik betrifft, ist die behauptung, kleinere datentypen (char/short) wären langsamer im zugriff bei heute eingesetzten prozessoren ein reines gerücht (unter bestimmten bedingungen traf das z.b. beim pentium pro zu). zumal mov-befehle existieren, die die nötige erweiterung des ergebnisses (signed oder unsigned) implizit und ohne zeitverlust durchführen. im übrigen hat die tatsache, dass integeroperationen in der regel eine promotion zumindest auf int erfordern, nur geringe relevanz auf maschinencodeebene, schließlich kann der optimikerer hier tun und lassen, was er will, solange das ergebnis davon nicht betroffen ist. es spricht hier also nichts dagegen, (signed/unsigned) char zu verwenden. dass das ganze nicht zwingend einen gewinn bringt, falls andere member der klasse dann zusätzliches padding erfordern, ist eine andere sache.



  • camper schrieb:

    ...falls andere member der klasse dann zusätzliches padding erfordern, ist eine andere sache.

    Imho werden mitlerweile alle Member auf 32bit gepaddet, zumindest war das mein Eindruck als ich mit Strukturen, welche ein Bestimmtes Layout im Speicher haben mussten, zu tun hatte. Um das Padding abzuschalten gibts beim gcc ne extra option ("__attribute__((packed))").
    Und es ist auch kein Gerücht, dass es langsamer wär, sondern Tatsache. Ein unaligned Speicherzugriff ist im Ausnahmefall eben langsamer, weil evtl. halt 2 * 4byte gelesen werden müssen.

    Aber gegen short spricht trotzdem nichts, wird intern wahrscheinlich eh ein 4byte datentyp draus...



  • bei std::size_t bin ich mir zwar net 100% sicher, aber C++ Referenz sind alle C standard header bei C++ im Namespace std. ("(available also with the names cstdio, cstdlib, cstring, ctime, cmath, with the only difference that if included thus their content is declared within the std namespace)")


  • Mod

    bluecode schrieb:

    camper schrieb:

    ...falls andere member der klasse dann zusätzliches padding erfordern, ist eine andere sache.

    Imho werden mitlerweile alle Member auf 32bit gepaddet, zumindest war das mein Eindruck als ich mit Strukturen, welche ein Bestimmtes Layout im Speicher haben mussten, zu tun hatte. Um das Padding abzuschalten gibts beim gcc ne extra option ("__attribute__((packed))").

    der compiler verändert die reihenfolge der member nicht - wenn also member mit verschiedenen alignment-voraussetzungen aufeinanderfolgen, so kann es immer wieder zu padding kommen, zumal die alignmentvoraussetzung einer struktur immer vom member mit den striktesten anforderungen bestimmt wird. diese behauptung widerspricht jedenfalls eindeutig meiner erfahrung, die nehme ich also nicht ohne nachvollziehbares beispiel hin (nat. kann man dieses verhalten durch entsprechende compilerswitches erhalten, ich gehe hier von standardverhalten aus).

    Und es ist auch kein Gerücht, dass es langsamer wär, sondern Tatsache. Ein unaligned Speicherzugriff ist im Ausnahmefall eben langsamer, weil evtl. halt 2 * 4byte gelesen werden müssen.

    das macht nun gleich überhaupt keinen sinn. erstens ging es um kleinere typen und nicht im alignment. unsinnig wird es besonders deshalb, weil kleinere typen geringere anforderungen an das alignment stellen und mit char existiert dieses problem sowieso nicht.

    Aber gegen short spricht trotzdem nichts, wird intern wahrscheinlich eh ein 4byte datentyp draus...

    'wahrscheinlich' klingt sehr nach halbwissen - und es ist eben auch falsch (jedenfalls auf unserer typischen PC-plattform).



  • dragon90# schrieb:

    rofl size_t
    nimm int

    int sucks! only size_t rocks 😉



  • camper schrieb:

    der compiler verändert die reihenfolge der member nicht

    Ich hab da auch nix davon geschrieben...

    camper schrieb:

    wenn also member mit verschiedenen alignment-voraussetzungen aufeinanderfolgen, so kann es immer wieder zu padding kommen

    meiner Erfahrung nach kommt es immer zum Padding, wenn des Ende eines Datentyps nicht 32bit aligned ist. Soll heißen, dass bei der folgenden Struktur

    struct t
    {
    unsigned char c;
    unsigned int i;
    };
    

    Das i nicht am offset 1, sondern erst am offset 4 zu finden ist, also wird der unsigned char c soz. größer. Das c wird auf 4byte vergrößert, weil wenn der Prozessor i an einer nicht 32bit allignten Stelle lesen würde, müsste er 2 * 4byte lesen, da er nicht jedes Byte im Speicher einzeln anspricht, sondern immer Blocks von 4byte größe einliest. Warum dann nicht gleich nen unsigned int/unsigned long nehmen?

    camper schrieb:

    (nat. kann man dieses verhalten durch entsprechende compilerswitches erhalten, ich gehe hier von standardverhalten aus).

    Das ist kein Compiler-switch sondern ein erweitertes Attrbut, welches nur zur Struktur gehört. Und mit diesem Attribut wird eben das Allignment nicht erzwungen (evtl. natürlich auf Kosten von geschwindigkeit).

    camper schrieb:

    ...weil kleinere typen geringere anforderungen an das alignment stellen und mit char existiert dieses problem sowieso nicht.

    Wenn ich tausend chars hintereinander in ne Struktur pack, dann passiert rein geschwindigkeitsmäßig natürlich nix, aber ich hab einfach mal antizipiert, dass man im Allgemeinen eben auch andere Typen nimmt.

    camper schrieb:

    'wahrscheinlich' klingt sehr nach halbwissen - und es ist eben auch falsch (jedenfalls auf unserer typischen PC-plattform).

    Ich kann ja nun wirklich nicht für jeden Compiler sprechen. Es gibt ja keinen Standard für sowas. Ich kann nur vom gcc sagen, dass er alles 32bit allignt.


  • Mod

    bluecode schrieb:

    meiner Erfahrung nach kommt es immer zum Padding, wenn des Ende eines Datentyps nicht 32bit aligned ist. Soll heißen, dass bei der folgenden Struktur

    struct t
    {
    unsigned char c;
    unsigned int i;
    };
    

    Das i nicht am offset 1, sondern erst am offset 4 zu finden ist, also wird der unsigned char c soz. größer. Das c wird auf 4byte vergrößert, weil wenn der Prozessor i an einer nicht 32bit allignten Stelle lesen würde, müsste er 2 * 4byte lesen, da er nicht jedes Byte im Speicher einzeln anspricht, sondern immer Blocks von 4byte größe einliest. Warum dann nicht gleich nen unsigned int/unsigned long nehmen?

    das ist doch eine etwas extreme verallgeimnerung vom einzelfall. es kommt immer dann zum padding, wenn das alignment des folgende members dies erfordert (oder die struktur zu ende ist und ihr alignment dies erfordert. der compiler wird also hier auf 32 bit padden WENN das folgende member 32bit alignment verlangt und der folgende offset sonst nicht entsprechend ausgerichtet wäre - diese fundamentale bedingung hast du bisher unterschlagen. also z.b.

    struct t1 {
    int i;
    char c; };  // 3 bytes padding da struktur 32bit alignment benötigt für int memberstruct t2 {
    char c;
    short s; }; // 1 byte padding für short
    struct t3 {
    char c1;
    char c2;
    short s; }; // kein padding;
    

    nichts davon liefert ein argument dafür, member größer zu machen, als nötig. wenn ich den gültigen wertebereich eines members kenne und dieser hinreichend klein ist - welchen gewinn sollte es bringen, einen größeren zahlenbereich zuzulassen? es ist sicher richtig, dass es manchmal keinen unterschied macht - aber es ist NIE ein gewinn.



  • camper schrieb:

    nichts davon liefert ein argument dafür, member größer zu machen, als nötig. wenn ich den gültigen wertebereich eines members kenne und dieser hinreichend klein ist - welchen gewinn sollte es bringen, einen größeren zahlenbereich zuzulassen? es ist sicher richtig, dass es manchmal keinen unterschied macht - aber es ist NIE ein gewinn.

    Die Ausgangsfragestellung war doch, ob er nach in casten soll (von short/char). Ich finds halt leichter lesbar und net so verwirrend, wenn möglichst auf casts verzichtet wird. Deshalb hab ich doch versucht zu sagen - was mir irgendwie nicht gelungen ist - das ein int nicht wirklich langsamer als short/char ist.



  • std::Robin schrieb:

    ich möchte in einer Klasse einige kleine Zahlen (1..16) speichern.
    Jetzt stellt sich mir die Frage ob ich als short als Datentyp oder char nehmen soll.
    Bei char ist aber immer ein static_cast nötig, was vielleicht auf die Performance gehen könnte.

    Wenn char vom Wertebereich her reicht, dann verwende es auch. Wobei du nicht char selbst nehmen solltest (repräsentiert ja ein Zeichen), sondern für Zahlen eher signed char oder unsigned char. Und warum du static_cast bei char verwenden musst, ist mir ehrlich gesagt noch ein Rätsel. char kann in jeden anderen integralen Typ implizit umgewandelt werden. Falls du die Zahlen mit int's weiterverarbeitest und der Speicherverbrauch egal ist, kannst du auch int nehmen. short würde ich eher nicht empfehlen, sofern es nicht wirklich notwendig ist (zB bei optimalem Kompromiss aus Wertebereich und Speicherverbrauch), da 16 Bit Befehle auf x32 CPUs einer Code Penalty unterliegen (zumindest im Protected Mode). Inwiefern das Auswirkungen auf die Verarbeitungsgeschwindigkeit hat, ist sicherlich von CPU zu CPU unterschiedlich und wird sich unter normalen Umständen sowieso nicht bemerkbar machen. Man muss sich ja aber nicht vollkommen unnötig mit Ballast beladen. 🙂

    bluecode schrieb:

    noch besser isses imho std::size_t zu nehmen.

    Nein, ist es nicht. size_t ist nicht dafür da, einfach nur ein paar Zahlen zu speichern.

    .filmor schrieb:

    In welchem Header ist das eigentlich definiert? Mein Compiler schluckt auch size_t (ohne std und ohne Includes)?!

    size_t wird durch den Header <cstddef> definiert. Ohne diesen sollte dein Compiler schon einen Fehler bringen, da Typen wie ptrdiff_t oder size_t kein grundlegender Bestandteil der Sprache sind, wie zB die diversen Schlüsselwörter. Zumindest ist mir nichts anderes bekannt. Logischer wäre es allerdings schon, immerhin liefert ptr1 - ptr2 ptrdiff_t und sizeof size_t.

    LordJaxom schrieb:

    Dass size_t sich im Namespace std befindet war mir btw auch neu

    Alle <c...> Header beinhalten die Bezeichner für C Kompatibilität und diese befinden sich sowohl im globalen als auch im std Namensraum. Es macht also keinen Unterschied, ob du size_t oder std::size_t schreibst. Wichtig ist nur #include <cstddef>.

    bluecode schrieb:

    Das i nicht am offset 1, sondern erst am offset 4 zu finden ist, also wird der unsigned char c soz. größer. Das c wird auf 4byte vergrößert

    Nein, c ist ein Byte und bleibt ein Byte. Hier wird überhaupt nichts vergrössert. Soviel zum Thema C++.
    Den evtl. durch Padding entstehenden ungenutzten Speicher kann der Compiler verwenden wie er lustig ist. Und wenn er c auf int vergrössert, weil es für ihn "günstiger" ist, dann kann er das natürlich machen. Das sind aber reine Internas und haben den Anwender überhaupt nicht zu interessieren, sofern Padding irrelevant ist. Für x32 CPUs sind jedenfalls Byte Zugriffe ziemlich billig. Es ist also sehr unwahrscheinlich, dass ein Compiler hier für c mehr als ein Byte verwendet. Wobei du natürlich Recht hast, dass i sehr wahrscheinlich an Offset 4 zu finden ist.



  • Vielen Dank an alle, aber die technischen Details sind mir zu hoch - ich verwende jetzt einfach unsigned short....

    groovemaster schrieb:

    Wenn char vom Wertebereich her reicht, dann verwende es auch. Wobei du nicht char selbst nehmen solltest (repräsentiert ja ein Zeichen), sondern für Zahlen eher signed char oder unsigned char. Und warum du static_cast bei char verwenden musst, ist mir ehrlich gesagt noch ein Rätsel.

    Nunja, folgender Code gibt bei mir ein A aus:

    unsigned char iii=65;
    	cout <<iii<<endl;
    

    Ich wollte aber Zahlen haben, und deswegen muss ich einen static_cast machen um an die Zahlen heranzukommen.
    Compiler: MinGW 5.0.2 unter WindowsXP

    Gruss
    R



  • groovemaster schrieb:

    Wenn char vom Wertebereich her reicht, dann verwende es auch. Wobei du nicht char selbst nehmen solltest (repräsentiert ja ein Zeichen), sondern für Zahlen eher signed char oder unsigned char. Und warum du static_cast bei char verwenden musst, ist mir ehrlich gesagt noch ein Rätsel.

    Des Rätsels Lösung ist ganz einfach - "char" (und seine Brüder) ist zwar ein einfacher Ganzzahltyp, mit dem auch ganz normal gerechnet werden kann, hat jedoch immer noch die Bedeutung "Zeichen" im Hintergrund - und deshalb sind die Stream-Operatoren für char so überladen, daß sie die ASCII-Darstellung des übergebenen Wertes anzeigen (int, short und Kollegen werden als Zahl aufgefasst und entsprechend behandelt).



  • Na wenn du nur was in die streams ausgeben willst, dann nimm char und caste.
    Die formatierte ausgabe ist so zeitaufwändig, da fällt der cast nicht ins gewicht.

    Das soll jetzt nicht heißen, dass du die nicht nehmen sollst, sondern dass du durch den cast nicht wirklich etwas gewinnst.



  • Hier gehen ja manche echt ab! 🙄 Bei Softwareentwicklung sollte man nicht nur an einzelne Bits denken oder an einen Taktzyklus. Der Sinn von Hochsprachen (auch C++) ist auch seinen Code lesbar und wartbar zu machen.

    Wenn eine Variable nur max. 16bit Werte aufnehmen soll, dann bitte auch einen entsprechenden Datentyp wählen. Denn schliesslich soll der Nutzer einer Variable, Funktion usw. am Typ sehen können, was er erwarten kann. Wenn ich ein long sehe, dann heißt das für mich, das ich auch den long-Bereich ausnutzen kann. Und nicht zur Laufzeit feststellen muß, das meine übergebenen Werte beschnitten werden oder sowas.



  • CStoll schrieb:

    Des Rätsels Lösung ist ganz einfach - "char" (und seine Brüder) ist zwar ein einfacher Ganzzahltyp, mit dem auch ganz normal gerechnet werden kann, hat jedoch immer noch die Bedeutung "Zeichen" im Hintergrund - und deshalb sind die Stream-Operatoren für char so überladen, daß sie die ASCII-Darstellung des übergebenen Wertes anzeigen

    Das ist aber ein Fehler in den Streams der STL, imo. Nur char bedeutet Zeichen, signed char und unsigned char sind Ganzzahltypen mit Bytegrösse und sollten von cout auch entsprechend ausgegeben werden.

    There are four signed integer types: “signed char”, “short int”, “int”, and “long int.”
    [...]
    For each of the signed integer types, there exists a corresponding (but different) unsigned integer type: “unsigned char”, “unsigned short int”, “unsigned int”, and “unsigned long int,”

    Leider sieht der Standard eine andere Funktionsweise der überladenen Operatoren vor.


Anmelden zum Antworten