C++ och Little Endian
- Johnny Rosenberg
- Inlägg: 1256
- Blev medlem: 23 jun 2007, 16:18
- OS: Ubuntu
- Utgåva: 22.10 Kinetic Kudu
- Kontakt:
C++ och Little Endian
Hej igen!
Har lite fler frågor när det gäller C++, som den nybörjare jag fortfarande är, även om jag nu börjat få lite ordning på det hela, med betoning på "lite".
Jag har ju tänkt att skriva ett terminalprogram som rotar och härjar lite i 24-bits wav-filer och en egenhet jag märkt med sådana filer är ju att all data ligger "baklänges", det man brukar kalla "Little Endian". Exempelvis är det hexadecimala talet ABCDEF lagrat som EFCDAB.
Är det någon som har något förslag på hur man enklast läser in sådant från filen till en variabel av typen long, så att EFCDAB konverteras till ABCDEF00? Vad jag är ute efter är i första hand vilken metod som går snabbast att exekvera, så wav-filer kan vara relativt stora. Kanske finns någon färdig funktion att använda för detta i något bibliotek som man kan hitta i något Ubuntuförråd eller som redan finns i standardbiblioteket?
Visst, det är ganska enkelt att göra en sådan konvertering, men finns det redan ett alternativ som gör programmet snabbare så är ju det att föredra.
Vad jag ska göra är ett program som behandlar vågformen i 24-bitars wavfiler på lite olika sätt, bland annat ska jag göra en brick-wall-limiter, eftersom jag hittills inte hittat någon sådan som varit godtagbar när det gäller ljudkvaliteten. Jag har länge förundrats över att det ska vara så svårt att göra en sådan när jag själv tycker att det borde vara otroligt lätt, och detta program ska då bevisa för mig om jag har rätt eller fel på den punkten... Men jag vill inte bara att det ska låta bra, det ska gå fort som självaste attan att köra programmet också... (det ska bara rassla till och så ska det vara klart, typ).
Jag har fler frågor om själva programmeringen, men de får nog egna trådar.
Har lite fler frågor när det gäller C++, som den nybörjare jag fortfarande är, även om jag nu börjat få lite ordning på det hela, med betoning på "lite".
Jag har ju tänkt att skriva ett terminalprogram som rotar och härjar lite i 24-bits wav-filer och en egenhet jag märkt med sådana filer är ju att all data ligger "baklänges", det man brukar kalla "Little Endian". Exempelvis är det hexadecimala talet ABCDEF lagrat som EFCDAB.
Är det någon som har något förslag på hur man enklast läser in sådant från filen till en variabel av typen long, så att EFCDAB konverteras till ABCDEF00? Vad jag är ute efter är i första hand vilken metod som går snabbast att exekvera, så wav-filer kan vara relativt stora. Kanske finns någon färdig funktion att använda för detta i något bibliotek som man kan hitta i något Ubuntuförråd eller som redan finns i standardbiblioteket?
Visst, det är ganska enkelt att göra en sådan konvertering, men finns det redan ett alternativ som gör programmet snabbare så är ju det att föredra.
Vad jag ska göra är ett program som behandlar vågformen i 24-bitars wavfiler på lite olika sätt, bland annat ska jag göra en brick-wall-limiter, eftersom jag hittills inte hittat någon sådan som varit godtagbar när det gäller ljudkvaliteten. Jag har länge förundrats över att det ska vara så svårt att göra en sådan när jag själv tycker att det borde vara otroligt lätt, och detta program ska då bevisa för mig om jag har rätt eller fel på den punkten... Men jag vill inte bara att det ska låta bra, det ska gå fort som självaste attan att köra programmet också... (det ska bara rassla till och så ska det vara klart, typ).
Jag har fler frågor om själva programmeringen, men de får nog egna trådar.
SV: C++ och Little Endian
Kod: Markera allt
#define _XOPEN_SOURCE
#include <unistd.h>
void swab(const void *from, void *to, ssize_t n);
The swab() function copies n bytes from the array pointed to by from to the array pointed to by to, exchanging adjacent even and odd bytes. This function is used to exchange data between
machines that have different low/high byte ordering.
This function does nothing when n is negative. When n is positive and odd, it handles n-1 bytes as above, and does something unspecified with the last byte. (In other words, n should be even.)
edit: hehe kanske ska ta å läsa hela ditt inlägg

Kod: Markera allt
uint32_t ntohl(uint32_t netlong);
Om du behöver väldigt mycket optimering så måste du nog hitta nåt som är skrivit i assembler som utnyttjar lite extra register, typ MMX registerna eller dylikt. Dock så kommer det inte att gå att porta till andra plattformar.
Senast redigerad av 1 gasol, redigerad totalt 15 gånger.
The Black Mountain Scorpion Hoedown Bluegrass Experience Gang
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
- Johnny Rosenberg
- Inlägg: 1256
- Blev medlem: 23 jun 2007, 16:18
- OS: Ubuntu
- Utgåva: 22.10 Kinetic Kudu
- Kontakt:
SV: C++ och Little Endian
Vad använder man _XOPEN_SOURCE till?gasol skrev:Kod: Markera allt
#define _XOPEN_SOURCE #include <unistd.h> void swab(const void *from, void *to, ssize_t n);
The swab() function copies n bytes from the array pointed to by from to the array pointed to by to, exchanging adjacent even and odd bytes. This function is used to exchange data between
machines that have different low/high byte ordering.
This function does nothing when n is negative. When n is positive and odd, it handles n-1 bytes as above, and does something unspecified with the last byte. (In other words, n should be even.)
edit: hehe kanske ska ta å läsa hela ditt inlägg
konverterar long till host order, dvs till little endian.Kod: Markera allt
uint32_t ntohl(uint32_t netlong);
Om du behöver väldigt mycket optimering så måste du nog hitta nåt som är skrivit i assembler som utnyttjar lite extra register, typ MMX registerna eller dylikt. Dock så kommer det inte att gå att porta till andra plattformar.
Ingår unistd.h i standarbiblioteket eller måste jag installera något ytterligare?
ntohl verkar ju bra, finns den också i unistd.h? Jag behöver konvertera åt båda hållen. Finns en hlton med också på ett hörn?
Vad menar du med "andra plattformar" i detta fall? Räknas en annan Linuxdistribution som en annan plattform? Att man inte kan porta till Windows ser jag som en stor fördel, vad gäller Mac är jag mer kluven.
Edit: Kom på ännu en följdfråga:
Finns det någon chans att med vanligt sunt förnuft skriva en egen funktion som är lika snabb som dessa "färdiga" funktioner eller har de någon fördel på något sätt, exempelvis att de är skrivna på ett mer maskinnära sätt, exempelvis i assembler?
Senast redigerad av 1 Johnny Rosenberg, redigerad totalt 15 gånger.
SV: C++ och Little Endian
Med plattform så menar jag hårdvaruplattform typ x86, SPARC osv... Detta är dock endast om du försöker att göra något plattforms specifikt. Vilket är vissa register kan vara.
Ett tips är att ladda hem man sidorna för libc. Där finns det massor av information till alla systemanrop som ingår.
Jag har ingen aning om hur dessa funktioner är skrivna ska ta en titt.
Ett tips är att ladda hem man sidorna för libc. Där finns det massor av information till alla systemanrop som ingår.
unistd.h ingår i libc.The htonl() function converts the unsigned integer hostlong from host byte order to network byte order.
The htons() function converts the unsigned short integer hostshort from host byte order to network byte order.
The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.
The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order.
Jag har ingen aning om hur dessa funktioner är skrivna ska ta en titt.
The Black Mountain Scorpion Hoedown Bluegrass Experience Gang
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
SV: C++ och Little Endian
Kod: Markera allt
#include <netinet/in.h>
#undef htonl
#undef ntohl
uint32_t
htonl (x)
uint32_t x;
{
#if BYTE_ORDER == BIG_ENDIAN
return x;
#elif BYTE_ORDER == LITTLE_ENDIAN
return __bswap_32 (x);
#else
# error "What kind of system is this?"
#endif
}
weak_alias (htonl, ntohl)
Well __bswap_32 verkar användas så efter lite snokande så hittade jag den på ett par olika ställen:
./sysdeps/i386/bits/byteswap.h
./sysdeps/ia64/bits/byteswap.h
./sysdeps/m68k/bits/byteswap.h
./sysdeps/s390/bits/byteswap.h
./sysdeps/x86_64/bits/byteswap.h
./sysdeps/generic/bits/byteswap.h
Koden för generic, detta fungerar alltså på vilken platform som helst, ett riktigt bra exempel på Gubb-C.
Kod: Markera allt
/* Swap bytes in 32 bit value. */
#ifdef __GNUC__
# define __bswap_32(x) \
(__extension__ \
({ unsigned int __bsx = (x); \
((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >> 8) | \
(((__bsx) & 0x0000ff00) << 8) | (((__bsx) & 0x000000ff) << 24)); }))
#else
static __inline unsigned int
__bswap_32 (unsigned int __bsx)
{
return ((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >> 8) |
(((__bsx) & 0x0000ff00) << 8) | (((__bsx) & 0x000000ff) << 24));
}
#endif
Okay nu tar vi en titt på i386 specifika koden och ser vad som händer där...
Kod: Markera allt
#define __bswap_constant_32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#ifdef __GNUC__
# if __GNUC__ >= 2
/* To swap the bytes in a word the i486 processors and up provide the
`bswap' opcode. On i386 we have to use three instructions. */
# if !defined __i486__ && !defined __pentium__ && !defined __pentiumpro__ \
&& !defined __pentium4__
# define __bswap_32(x) \
(__extension__ \
({ register unsigned int __v, __x = (x); \
if (__builtin_constant_p (__x)) \
__v = __bswap_constant_32 (__x); \
else \
__asm__ ("rorw $8, %w0;" \
"rorl $16, %0;" \
"rorw $8, %w0" \
: "=r" (__v) \
: "0" (__x) \
: "cc"); \
__v; }))
# else
# define __bswap_32(x) \
(__extension__ \
({ register unsigned int __v, __x = (x); \
if (__builtin_constant_p (__x)) \
__v = __bswap_constant_32 (__x); \
else \
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); \
__v; }))
# endif
# else
# define __bswap_32(x) \
(__extension__ \
({ register unsigned int __x = (x); __bswap_constant_32 (__x); }))
# endif
#else
static __inline unsigned int
__bswap_32 (unsigned int __bsx)
{
return __bswap_constant_32 (__bsx);
}
#endif
Men här finns det ett fint litet sätt att swap ett "ord" (32-bitar)
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x));
Som kommentaren säger så finns det en assembly swap instruktion på 486 och uppåt...
Så om vi har kompilerat mot denna version så kommer det nog gå bra mycket snabbare
om det ska göras mycket swappande. Om det inte finns något stöd för assembly swap:andet
så faller man ändå tillbaka på en mjukvaru metod!
edit: DAMN vad skoj det är att köra ett GNU/Linux system där man kolla på källan till system och alla bibliotek ^_^
Senast redigerad av 1 gasol, redigerad totalt 16 gånger.
The Black Mountain Scorpion Hoedown Bluegrass Experience Gang
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
- Johnny Rosenberg
- Inlägg: 1256
- Blev medlem: 23 jun 2007, 16:18
- OS: Ubuntu
- Utgåva: 22.10 Kinetic Kudu
- Kontakt:
SV: C++ och Little Endian
Intressant, ska se om det är något jag kan använda. Undrar ibland varför kod man hittar på nätet och i sin dator har så otroligt jobbiga variabelnamn, men det kanske bara är jag som tycker det. Tänk om man kunde tvinga alla att slita loss "_"-tangenten från tangentbordet och aldrig använda den igen, men tyvärr så finns ju "-" på samma tangent på ett svenskt tangentbord och förmodligen något annat oumbärligt tecken på andra länders tangentbord...
Tack för att du orkade gräva fram detta!
J.R.
Tack för att du orkade gräva fram detta!
J.R.