C++ och Little Endian

Här diskuteras programmering och utveckling
Användarvisningsbild
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

Inlägg av Johnny Rosenberg »

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.
Vänliga hälsningar

Johnny Rosenberg
ジョニー・ローゼンバーグ

IEEE 1541 - binära prefix
ISO 8601 - datum och tid
Användarvisningsbild
gasol
Inlägg: 405
Blev medlem: 27 jul 2007, 14:57
Kontakt:

SV: C++ och Little Endian

Inlägg av gasol »

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 :P

Kod: Markera allt

uint32_t ntohl(uint32_t netlong);  
konverterar long till host order, dvs till little endian.

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.
Användarvisningsbild
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

Inlägg av Johnny Rosenberg »

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 :P

Kod: Markera allt

uint32_t ntohl(uint32_t netlong);  
konverterar long till host order, dvs till little endian.

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.
Vad använder man _XOPEN_SOURCE till?
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.
Vänliga hälsningar

Johnny Rosenberg
ジョニー・ローゼンバーグ

IEEE 1541 - binära prefix
ISO 8601 - datum och tid
Användarvisningsbild
gasol
Inlägg: 405
Blev medlem: 27 jul 2007, 14:57
Kontakt:

SV: C++ och Little Endian

Inlägg av gasol »

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.
      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.
unistd.h ingår i libc.

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.
Användarvisningsbild
gasol
Inlägg: 405
Blev medlem: 27 jul 2007, 14:57
Kontakt:

SV: C++ och Little Endian

Inlägg av gasol »

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)
Här är koden för htonl ganska lättläsligt, jag hade förväntat mig mer gubb-C här.
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
Så här löser vi swappandet med lite shiftningar och OR:de

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

Okay här börjar det bli riktigt jobbigt att läsa skiten... mkt #IFDEF ^_^

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.
Användarvisningsbild
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

Inlägg av Johnny Rosenberg »

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.
Vänliga hälsningar

Johnny Rosenberg
ジョニー・ローゼンバーグ

IEEE 1541 - binära prefix
ISO 8601 - datum och tid
Skriv svar

Återgå till "Programmering och webbdesign"