[C] Xcode endianness probleem

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 12:16
Ik probeer een binair bestand in te lezen in C. Deze is opgeslagen met een big-endian bytevolgorde.
Nou lees ik een waarde en als ik deze omreken in bits klopt die ook MITS de bytevolgorde omgedraaid word.
Na even zoeken zie ik dat intel core2duo macs little-endian zijn en daar zal het probleem ook wel zitten.

Is het mogelijk om aan te geven in C code dat de stream als big-endian gelezen moet worden. Of in Xcode of enige andere oplossing (eventueel op linux oid). Ik zou wel graag de gcc compiler willen blijven gebruiken.

Als voorbeeld. Ik lees: 5987076 en dat zou eigenlijk 285531 moeten zijn.

Little-endiann schijnt ook een gcc compiler default te zijn?

[ Voor 5% gewijzigd door Gehakt op 30-10-2009 10:31 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Gehakt schreef op vrijdag 30 oktober 2009 @ 10:28:
Is het mogelijk om aan te geven in C code dat de stream als big-endian gelezen moet worden.
Dat zou ontzettend onzinnig zijn, want het bestand lees je binair in, en de binaire representatie is op beide soorten machines exact identiek. Waar het fout gaat is dat jij stukken binaire data gaat interptereren als bepaalde datatypes. De standard library kan niet zien dat jij dat doet en ook de compiler heeft er geen weet van, en dus bestaat er ook geen mogelijkheid om dat in te stellen.

Je zult de data zelf moeten converteren. Handiger is als je gewoon bepaalde functies maakt (zoals readInt() etc.) die de data na het lezen direct voor je omkeert. Als je in een keer een struct uitleest zul je elke member om moeten draaien.

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.


Acties:
  • 0 Henk 'm!

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 12:16
Om het even te verduidelijken ik probeer library te schrijven die werkt met data opgeslagen volgens de OpenLR standaard. http://www.tomtom.com/lib/OpenLR/OpenLR-whitepaper.pdf

Hier staat een voorbeeld stream in die van links naar rechts, boven naar beneden gelezen moet worden. (pagina 40):

code:
1
2
3
4
00001010 00000100 01011011 01011011 00100011 01000110
11110100 00011010 01101100 00001001 00000000 10011011
11111110 00111011 00011011 10110100 00000100 11111111
11101011 11111111 10100011 00101011 01011001 00000010


Lon is de 2e 3e en 4e byte.
code:
1
2
3
Byte  First                Second                         Third
Bit     7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Value 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1

Lees ik dus als:
code:
1
 0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1 0 0 0 0 0 1 0 0


Hoe kan ik controleren of mijn bestand dat ik heb opgeslagen ook bit voor bit klopt? zijn hier programmas voor of zal ik hem bit voor bit moeten outputten met een C functie? En waar zit nu de fout. Bij mij, mijn code, de compiler of architectuur.

Aan het eind wil ik dus een functie hebben die ik een stuk geheugen kan geven en hij de juiste waarde (uiteraard) uitleest.
.oisyn schreef op vrijdag 30 oktober 2009 @ 10:33:
[...]
Je zult de data zelf moeten converteren. Handiger is als je gewoon bepaalde functies maakt (zoals readInt() etc.) die de data na het lezen direct voor je omkeert. Als je in een keer een struct uitleest zul je elke member om moeten draaien.
Als ik het dus goed begrijp moet ik in alle gevallen. ook als ik een stuk geheugen aan zou bieden de gelezen waarden om gaan draaien? Gaat dat dan weer niet fout zodra de library/code op een andere architectuur gebruikt word.
.oisyn schreef op vrijdag 30 oktober 2009 @ 10:55:
en het bronbestand heeft een andere endianness dan je platform, dan moet je die bytes omdraaien.
Ah dat gaat dus inderdaad fout op een ander platform. Dan heb ik nog een paar vragen:
  • Wat is de makkelijkste manier om te controlleren of de bitstream in de juiste volgorde in het bestand staat. Bit voor bit printen door middel van bitmasks? Apart (gratis) programma?
  • Is er iets van een compiler macro waar de endianess instaat zodat ik er rekening mee kan houden met programmeren. if (big) { doe niks(); } if (little) { draaiom(); }

[ Voor 44% gewijzigd door Gehakt op 30-10-2009 11:03 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het punt is dat je zelf de moete moet doen om de bytes om te keren. Als jij de 2e, 3e en 4e byte in een int moet gieten, en het bronbestand heeft een andere endianness dan je platform, dan moet je die bytes omdraaien.

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.


Acties:
  • 0 Henk 'm!

  • Icelus
  • Registratie: Januari 2004
  • Niet online
Bij Apple zit dit al in de bibliotheek: Core Endian.
Endianness-type zul je wel zelf moeten uitzoeken.

Developer Accused Of Unreadable Code Refuses To Comment


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

[quote]Gehakt schreef op vrijdag 30 oktober 2009 @ 10:48:
• Wat is de makkelijkste manier om te controlleren of de bitstream in de juiste volgorde in het bestand staat. Bit voor bit printen door middel van bitmasks? Apart (gratis) programma?
Tja, ik gebruik daar gewoon de debugger voor, of een hex editor.
• Is er iets van een compiler macro waar de endianess instaat zodat ik er rekening mee kan houden met programmeren. if (big) { doe niks(); } if (little) { draaiom(); }
GCC definieert __BIG_ENDIAN__ als het platform big endian is, maar beter kun je even naar de tip van Icelus luisteren ;). Dus als je een 32 bits unsigned int wilt omzetten die uit het bestand komt, kun je EndianU32_BtoN() aanroepen, zodat de endianness op beide platforms goed geconverteerd wordt (die functie doet namelijk niets op een big endian platform, en hij draait de data om op een little endian platform)

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.


Acties:
  • 0 Henk 'm!

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 12:16
Ontzettend handige tip en in principe echt waar ik naar op zoek ben. Maar dat maakt de code wel direct mac afhankelijk? Er is zo te zien ook een endian.h voor linux maar kan niet vinden of die dezelfde functies bevat.

Zo niet dan is het pech en ga ik gewoon voor de Mac oplossing.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Tja, als je cross OS code wil dan kun je dat op zich nog wel vrij gemakkelijk zelf implementeren met de __BIG_ENDIAN__ macro. Alleen is het wel vrij veel werk om al die functie permutaties in te typen ;)

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.


Acties:
  • 0 Henk 'm!

  • Icelus
  • Registratie: Januari 2004
  • Niet online
Gehakt schreef op vrijdag 30 oktober 2009 @ 11:41:
Ontzettend handige tip en in principe echt waar ik naar op zoek ben. Maar dat maakt de code wel direct mac afhankelijk? Er is zo te zien ook een endian.h voor linux maar kan niet vinden of die dezelfde functies bevat.

Zo niet dan is het pech en ga ik gewoon voor de Mac oplossing.
De Linux versie is niet hetzelfde IIRC.
Je kunt natuurlijk ook je eigen endian bibliotheek schrijven; dan zal het op ieder platform werken.

Wees voorzichtig met de _BIG_ENDIAN_ macro. Apple is bezig met een nieuwe compiler (al te gebruiken in Snow Leopard). Weet niet of deze macro aanwezig is/blijft.

Developer Accused Of Unreadable Code Refuses To Comment


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik dacht eigenlijk dat het een GCC macro was, en geen MacOS specifieke macro?

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.


Acties:
  • 0 Henk 'm!

  • Icelus
  • Registratie: Januari 2004
  • Niet online
.oisyn schreef op vrijdag 30 oktober 2009 @ 12:04:
Ik dacht eigenlijk dat het een GCC macro was, en geen MacOS specifieke macro?
Je hebt gelijk. Ik meende dat LLVM een nieuwe compiler was maar het is een aparte optimalisatie en codegenerator voor GCC. De macro is dan wel een nette oplossing.

Developer Accused Of Unreadable Code Refuses To Comment


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 07:06
Apple is wel bezig met het ontwikkelen van een nieuwe compiler front-end om gcc te vervangen: Clang. (Beter gezegd: Apple sponsort het project). Clang maakt ook gebruik van LLVM als code generator.

[ Voor 10% gewijzigd door Jaap-Jan op 30-10-2009 12:34 ]

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 12:16
Ik denk dat ik eerst even kijk hoeveel werk het is om mijn eigen specifieke functies te schrijven met de macro. Als het echt veel tijd bespaard gebruik ik de endian library wel.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 03:13
Er zijn ook functies als htons, htonl, ntohs en ntohl waarmee je 16 en 32-bits integers kunt converteren van host naar network byte order (big endian) en vice versa. Die functies doen niets op een big-endian platform, en swappen bytes op een little-endian platform. Daarmee hoef je in principe niets zelf te schrijven. (Bijkomend voordeel is dat b.v. glibc ze heel efficiënt implementeert, door inline assembly code te genereren op basis van de target cpu.)

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Daarnaast is het voordeel van die functies dat ze beschikbaar zijn voor *nix als wel Windows

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het jammere is alleen dat er geen little-endian counterparts zijn.

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.


Acties:
  • 0 Henk 'm!

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 12:16
Het probleem is dat het hier niet om standaard 16 of 32 bits gaat. De OpenLR standaard is zo compact mogelijk beschreven dus als een waarde in 24 bits past hebben ze die gebruikt. Maar zover ik kan zien hoef ik alleen een functie te schrijven die 3byte omdraait en een functie die 2 byte omdraait.

Met behulp van pointers lukt dit wel. Door zelf de code te schrijven binnen een #if __LITTLE_ENDIAN__ macro hoop ik een beetje platformonafhankelijk te blijven.
Moet het nog even testen op linux. Windows heb ik zoiezo al afgeschreven om een andere reden.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 03:13
Schrijf dan gewoon je eigen readInt32/24/16 functies zoals .oisyn voorstelde. Je hebt waarschijnlijk toch geen 24-bits integers, dus ligt het voor de hand een functie te schrijven als:
C:
1
2
3
4
5
int read_int24(FILE *fp)
{
    int a = getc(fp), b = getc(fp), c = getc(fp);
    return (a << 16) | (b << 8) | (c << 0);
}

off-topic:
Quizvraag: waarom schrijf ik dit niet als volgt?
C:
1
2
3
4
int read_int24(FILE *fp)
{
    return (getc(fp) << 16) | (getc(fp) << 8) | (getc(fp) << 0);
}

(.oisyn mag niet meeraden :P)

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat flauw :+

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.


Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 09:04
De | operator is in C commutatief, wat wil zeggen dat de uitkomst van de expressie hetzelfde is wanneer de operanden verwisseld zouden worden. Een compiler kan daar in het kader van optimalisatie toe besluiten en daardoor bijvoorbeeld de eerste char die met getc() wordt gelezen te gebruiken voor de getc(fp) << 0 subexpressie. In de eerste variant is dat niet mogelijk omdat de waarde voor de subexpressie c << 0 (beetje overbodig trouwens die shift met 0...) altijd de als derde gelezen char uit fp is.

...wat heb ik gewonnen?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Niets, het is namelijk niet helemaal goed. Je komt in de buurt though ;), je conclusie klopt namelijk, je argumentatie alleen niet.

Doen a() en b() hier hetzelfde?
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
int foo();

int a()
{
    return foo() / foo();
}

int b()
{
    int v1 = foo();
    int v2 = foo();
    return v1 / v2;
}

[ Voor 79% gewijzigd door .oisyn op 31-10-2009 01:40 ]

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.


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Dat ligt er aan wat foo met de global state doet.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 09:04
.oisyn schreef op zaterdag 31 oktober 2009 @ 01:35:
Niets, het is namelijk niet helemaal goed. Je komt in de buurt though ;), je conclusie klopt namelijk, je argumentatie alleen niet.
Jammer... 't is al laat he. Dan is 't dat de | operator geen sequence point is :)

Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 07:06
Aah, ik ben erachter, 't was wel een kwartier puzzelen. :P

In C en C++ is niet gedefinieerd in welke volgorde subexpressies moeten worden geëvalueerd (met uitzondering van de &&, ||, ?:, en , operatoren). De mogelijkheid bestaat dus dat de compiler dat van rechts naar links doet, waardoor eerst de subexpressie (getc(fp) << 0) wordt geëvalueerd en het resultaat dus niet klopt.

edit:
Stik, ik had het linkje van matthijsln niet gelezen. :P

[ Voor 15% gewijzigd door Jaap-Jan op 31-10-2009 03:54 ]

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

NC83 schreef op zaterdag 31 oktober 2009 @ 02:22:
Dat ligt er aan wat foo met de global state doet.
Je antwoord is dus dat ze niet equivalent zijn, gegeven dat je niet weet wat foo() doet? ;)
matthijsln schreef op zaterdag 31 oktober 2009 @ 02:27:

Jammer... 't is al laat he. Dan is 't dat de | operator geen sequence point is :)
d:)b

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