Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.

[C++] shift gedrag

Pagina: 1
Acties:

  • PoweRoy
  • Registratie: April 2002
  • Laatst online: 21:09
Ik ben bezig met data verwerken. Deze data wordt aangegeven in een unsigned char array (als in unsigned char* data).

In dit geval staat er een 40 bits getal in deze array. Op plaats 4 t/m 8. Hoe sla ik deze op in een int64_t :?

C++:
1
2
3
4
5
m_UTCTime  = data[8];
m_UTCTime += data[7] << 8;
m_UTCTime += data[6] << 16;
m_UTCTime += data[5] << 24;
m_UTCTime += data[4] << 32


Als ik een unsigned char met 8 naar links shift, wordt het dan in een temp variable opgeslagen waar het in past? Als in een 16 bits getal (of groter) ? Of wordt het bewaard in een dezelfde soort variable als waar de shift op gebaseerd is. unsigned char met 8 shiften wordt dan (altijd) 0.

C++:
1
2
3
4
5
6
7
8
9
10
11
int64_t tempdata;

m_UTCTime  = data[8];
tempdata = data[7];
m_UTCTime += data[7] << 8;
tempdata = data[6];
m_UTCTime += tempdata << 16;
tempdata = data[5];
m_UTCTime += tempdata << 24;
tempdata = data[4];
m_UTCTime += tempdata << 32;


Hiermee omzeil ik het probleem. Maar wat is het gedrag van het eerste stukje code en kan ik het forceren om in een groter getal te zetten? Typecasten oid?

[This space is for rent]


  • Cascade
  • Registratie: Augustus 2006
  • Laatst online: 11-11 11:41
Je kan zoiets proberen:

C++:
1
m_UTCTime += ((int64_t)data[7]) << 8;

Belangrijk is om te casten voordat je gaat shiften, anders gooi je bits weg.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

PoweRoy schreef op dinsdag 16 september 2008 @ 11:27:
Als ik een unsigned char met 8 naar links shift, wordt het dan in een temp variable opgeslagen waar het in past? Als in een 16 bits getal (of groter) ? Of wordt het bewaard in een dezelfde soort variable als waar de shift op gebaseerd is. unsigned char met 8 shiften wordt dan (altijd) 0.
Chars en shorts worden gepromote naar int. Die hoogstwaarschijnlijk 32 bits is op jouw systeem, waarbij het met een shift van 32 bits dus fout gaat. Door de operand van de shift van tevoren te converteren naar een type dat groot genoeg is (int64_t) kun je dat voorkomen, zoals Cascade al laat zien.

[ Voor 12% gewijzigd door .oisyn op 16-09-2008 11:51 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • writser
  • Registratie: Mei 2000
  • Laatst online: 19:53
Je moet inderdaad casten _voordat_ je shift, zoals de rest al aangeeft. Ik vraag me af: kun je de hele 5 bytes niet in een keer interpreteren als int64? Dus iets als:

C++:
1
2
int64_t * tijdpointer = (int64_t *) &data[4];
int64_t tijd = *tijdpointer >> 24


offtopic:
Disclaimer: ik heb geen compiler bij de hand en weet niet of dit werkt, laat staan of het portable is. :P

[ Voor 12% gewijzigd door writser op 16-09-2008 12:31 ]

Onvoorstelbaar!


  • PoweRoy
  • Registratie: April 2002
  • Laatst online: 21:09
Dus toch casten :) Zat te denken aan typecasten van pointers waar het object hetzelfde blijft alleen op een andere manier aanspreekt.
writser schreef op dinsdag 16 september 2008 @ 11:59:
Je moet inderdaad casten _voordat_ je shift, zoals de rest al aangeeft. Ik vraag me af: kun je de hele 5 bytes niet in een keer interpreteren als int64? Dus iets als:

C++:
1
2
int64_t * tijdpointer = (int64_t) &data[4];
int64_t tijd = *tijdpointer >> 24


offtopic:
Disclaimer: ik heb geen compiler bij de hand en weet niet of dit werkt, laat staan of het portable is. :P
Enge code/lastig leesbare code. Ik hou het bij mijn paar regels ;)

Bedankt voor de reacties!

[This space is for rent]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het werkt niet (je moet natuurlijk wel naar het juiste type casten op regel 1), en het is niet portable want A) het is undefined behaviour en B ) afhankelijk van de endianness van je systeem.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 18:33
writser schreef op dinsdag 16 september 2008 @ 11:59:
offtopic:
Disclaimer: ik heb geen compiler bij de hand en weet niet of dit werkt, laat staan of het portable is. :P
Portable is het sowieso niet

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • writser
  • Registratie: Mei 2000
  • Laatst online: 19:53
Daar was ik al bang voor :).

Onvoorstelbaar!


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Het hangt ook nog van de alignment af; kan aardig crashen op sommige systemen.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 20:55
Je kunt het probleem ook omzeilen door het shiften andersom te doen:
C:
1
2
3
4
5
6
7
8
9
m_UTCTime = data[4];
m_UTCTime <<= 8;
m_UTCTime |= data[5];
m_UTCTime <<= 8;
m_UTCTime |= data[6];
m_UTCTime <<= 8;
m_UTCTime |= data[7];
m_UTCTime <<= 8;
m_UTCTime |= data[8];

Je hoeft nu helemaal niet meer na te denken over de grootte van de elementen van de data-array, want die worden nu niet meer geshift. Je bent zo dus niet afhankelijk van de grootte van types (behalve dat m_UTCTime natuurlijk minstens 40 bits groot moet zijn).

Een alternatieve constructie zou dit zijn:
C++:
1
2
3
4
5
m_UTCTime = (uint64_t)data[4]<<32 |
            (uint64_t)data[5]<<24 |
            (uint64_t)data[6]<<16 |
            (uint64_t)data[7]<< 8 |
            (uint64_t)data[8];

Welke je kiest is vooral een kwestie van stijl: de eerste code geeft een aantal statements die beschrijven hoe m_UTCTime berekend kan worden (wat niet betekend dat de compiler geen optimalisaties zal doen dat die een andere executie opleveren) terwijl de tweede code meer declaratief is en aangeeft hoe het resultaat opgebouwd is, en je het aan de compiler overlaat om de meest zinnige manier om de expressie uit te rekenen te bedenken.

  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 01-11 22:03

leuk_he

1. Controleer de kabel!

andere manier om bytes te benaderen ZONDER shift is met een unions

code:
1
2
3
4
5
6
7
8
9
typedef union
{
int64_t m_UTCTime;
char    m_bytesdata[8];
}dataun;
 
dataun mydata;

mydate.m_bytesdata[3]=12;


(voor complexere data goed op de padding settings van de compiler letten)

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nogmaals, dat is niet endian-safe. De data van PoweRoy is big-endian, gezien de manier hoe hij de bits in de int plaatst. Op een intel machine, welke little-endian is, werkt jouw manier niet, omdat de bytes dan verkeerd om staan.

[ Voor 74% gewijzigd door .oisyn op 16-09-2008 14:22 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 01-11 22:03

leuk_he

1. Controleer de kabel!

.oisyn schreef op dinsdag 16 september 2008 @ 14:20:
Nogmaals, dat is niet endian-safe. De data van PoweRoy is big-endian, gezien de manier hoe hij de bits in de int plaatst. Op een intel machine, welke little-endian is, werkt jouw manier niet, omdat de bytes dan verkeerd om staan.
Bytes uit een uint64 halen is zinloos als je niet de bytes nodig hebt.

Als je de meest significant nodig heb gewoon delen door 2^32 als je de minst significante bute nodig heb mod ("%") 2^32 doen.

Dat bedoel je met endian proof maken? (the horror wanneer je ook nog eens met signed numbers gaat werken...)

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


  • kenneth
  • Registratie: September 2001
  • Niet online

kenneth

achter de duinen

Endianness heeft te maken met op in welke volgorde waardes worden opgeslagen: begin je bij de MSB (big-endian) of bij de LSB (little-endian).

In dit soort conversies kan je opeens totaal andere getallen als uitkomst krijgen omdat er geen rekening wordt gehouden met of de gegevens big- of little-endian binnenkomen.

Bijvoorbeeld het getal 0x01020304 wordt op Intel-architecturen (little-endian) zo opgeslagen:


geheugenadreswaarde
000104
000203
000302
000401


En op big-endianarchitecturen als volgt:

geheugenadreswaarde
000101
000202
000303
000404


Wat je dus kan krijgen is dat je een reeks van bytes (0x01; 0x02; 0x03; 0x04) als little-endian interpreteert terwijl het big-endian is, en je eindigt met 0x04030201 ipv 0x01020304.

Daarom zijn unions vrijwel nooit bruikbaar in dit soort situaties.

Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

leuk_he schreef op dinsdag 16 september 2008 @ 14:37:

Bytes uit een uint64 halen is zinloos als je niet de bytes nodig hebt.
:?
Het ging om bytes in een uint64 stoppen...
Als je de meest significant nodig heb gewoon delen door 2^32, als je de minst significante bute nodig heb mod ("%") 2^32 doen
Ah, bedoel je dat. Dat is ook een issue, maar het ging hier om de individuele bytes die verkeerd om staan, niet 32-bit words in de dword.
Dat bedoel je met endian proof maken? (the horror wanneer je ook nog eens met signed numbers gaat werken...)
Nee dus, zie de reactie van kenneth. En signed numbers zijn helemaal niet moeilijker, je moet de top bit alleen even replicaten. Kun je makkelijk doen door de bytes in de bovenste 32 bits van de int te zetten, en dan een arithmetic right shift uit te voeren (helaas geeft C++ dan wel weer geen garanties of >> een logical of arithmetic shift is)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1