byte inverteren ?


Meeste compilers vervangen ook delen/vermenigvuldigen met een macht van twee door shifts right/left omdat dat veel efficienter is...

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

@Arco,

Dus

code:

 unsigned char inv_byte = ~byte;

levert hetzelfde resultaat op als

code:

 unsigned char inv_byte = byte ^ 0x0F;

Weer wat geleerd.

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Ik neem aan dat je 0xFF bedoelt ;-)

Het is overigens niet gegarandeerd dat de compiler hier dezelfde code voor genereert, maar een beetje fatsoenlijke compiler zal dat wel doen.

De https://godbolt.org/ site is wel leuk om te zien wat voor code de compiler genereert, zeker als optimalisaties aan staan (-O2) dan zie je dat de compiler af en toe best "slim" kan zijn.

Dan had ik geschreven '0xFF', maar ik schrijf '0x0F'. Volgens Arco maakt het niet uit welk getal je pakt omdat XOR ingrijpt op de hele byte. Volgens flipflop worden alleen bepaalde aangewezen bitjes getoggeld.

Bezoek mijn neefjes' site: www.tinuselectronics.nl
Sine

Moderator

Lijkt me niet, dan xor je alleen de bitjes die hoog staan, en bij 0F zijn dat er een paar minder ...

Hensz

Golden Member

Op 23 mei 2020 22:53:20 schreef ohm pi:
omdat XOR ingrijpt op de hele byte

Een XOR werkt op een hele byte, maar daarvoor wil hij ook een hele byte input. Corresponderende bits worden ge-exord, bit 0 met bit 0, bit 1 met bit 1 etc.
0xFF inverteert alle bits, 0x0F alleen de rechtse 4. 0x00 inverteert niets, zo zijn er nog 253 variaties. :+

Don't Panic!

Dus flipflop heeft gelijk?

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Met tilde (~) inverteer je alle bits, met een dakje (^) kan je kiezen welke bits geïnverteerd worden, in het geval van 0xFF zijn dit alle bits in een byte, in het geval van 0x0F enkel de 4 laagste bits.

Het is met xor natuurlijk logisch dat je het mask even lang kiest als de variabele...

Volgens Arco maakt het niet uit welk getal je pakt omdat XOR ingrijpt op de hele byte.

Dat doet 'ie ook. Dus als je maar een halve byte opgeeft (0x0F) dan xor't 'ie ook maar een halve byte...

[Bericht gewijzigd door Arco op 24 mei 2020 00:17:35 (55%)]

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

Op 23 mei 2020 21:28:39 schreef ohm pi:
Dit kan ook:

code:

 unsigned char inv_byte = 255 - byte;

Effe muggeziften: Dit werkt alleen als een char 8 bits is. Strikt genomen is een char minimaal 8 bits, maar mag meer zijn.

De tilde inverteert alle bits van de char.

En als je een datatype nodig hebt van exact 8 bits, dan gebruik je uint8_t (even #include <stdint.h> doen).

Op 23 mei 2020 23:09:22 schreef ohm pi:
Dus flipflop heeft gelijk?

Moet je dat vragen? :7
Zonder gekheid, op zich geeft de verwarring die hierboven ontstaat ook precies aan wat de voor en nadelen van beide opties zijn. De XOR doet een xor functie, en dan inverteer je alleen de bits die je xor't met een '1'. Een xor met '0' levert geen inversie op.
De ~ doet per definitie de hele variabele, want dat is in de syntax van 'C' zo afgesproken. Ik vind deze optie beter omdat het minder foutgevoelig is. Stel je maakt van de variabele een int ipv een char, dan blijft de ~ gewoon werken, maar je xor gaat mis, tenzij je de breedte ook aanpast. Ja, je moet geen fouten maken... nee, klopt :-)

@blurp: mag ik meedoen met muggeziften? Een char is minimaal 7 bits, de rest is bonus.

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

A char in C/C++ is minimaal 8 bits. Maar kan soms signed zijn (-128 .. +127) en soms unsigned (0..255), afhankelijk van compiler settings.

7 bits is de definitie van ASCII tabel. Dat staat los van de C/C++ definitie.

@flipflop: Muphry's law :-)

Even serieus, omdat dit een elektronica forum is en niet een visual basic forum, TS vroeg dit omdat hij waarschijnlijk hardware heeft waar 8 bitjes uitkomen of ingaan, en die moeten geinverteerd worden.

Dus in de applicatie van TS ligt het sowieso vast dat het 8 bitjes zijn. (of 6, of 7. Dat maakt niet uit. Relevant is dat vanuit de hardware (de werkelijkheid) vastligt hoeveel bits er zijn.)

In zo'n geval is het beter een uint8_t type te gebruiken dan een char. Inderdaad is een uint8_t in iedere implementatie van de C-compiler die ik ooit gezien heb gewoon een unsigned char, maar daar gaat het niet om.

Door een uint8_t te gebruiken geef je duidelijk aan dat het om een exact aantal bits gaat. Een "char" is voor letters en cijfers.

Ja, het is goed IN de code al eea te documenteren.

Zo documenteer ik met:

code:


static int status; 

dat de beginwaarde hiervan niet van belang is voor mij programma, en

code:


static int status=0; 

dat de beginwaarde WEL belangrijk is voor mijn programma.

En zoals Blurp voorstelt kan je met

code:


char c;

een variabele declareren waar je 1 karakter in opslaat... en met

code:


uint8_t c; 

een variabele waar je precies 8 bitjes in verwacht.

Het wordt vervelend als de compiler dan met dingen als memcpy of strcpy gaat zeuren:

code:


warning: pointer targets in passing argument 1 of ‘tests’ differ in signedness
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 24 mei 2020 07:06:34 schreef blurp:
[...]

Effe muggeziften: Dit werkt alleen als een char 8 bits is.

Je hebt helemaal gelijk. Als je een bijv 32-bits variabele kiest, dan moet je 0xFF veranderen in 0xFFFFFFFF enz.

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Op 23 mei 2020 22:10:01 schreef Arco:
[...]
Met XOR ook, geen verschil... (wat dacht je dat die tilde 'onder de motorkap' doet?... ;) )

Effe getest met https://godbolt.org/z/A6a69_
tilde levert totaal andere code op als xor. Is ook wel logisch, want tilde grijpt in op het hele byte en xor alleen op aangewezen bitjes. Het hangt ook af voor welke processor je compileert. Heeft de processor een instructie voor xor of niet en heeft de processor een instructie voor tilde?

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Op 24 mei 2020 19:12:50 schreef ohm pi:
Als je een bijv 32-bits variabele kiest, dan moet je 0xFF veranderen in 0xFFFFFFFF enz.

code:


int main (int argc, char **argv)
{
  int v;

  v = 0xaa;
  v ^= 0xff;

  printf ("%x\n", v);
  exit (0);
}

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 24 mei 2020 19:25:54 schreef ohm pi:
[...]Effe getest met https://godbolt.org/z/A6a69_
tilde levert totaal andere code op als xor. Is ook wel logisch, want tilde grijpt in op het hele byte en xor alleen op aangewezen bitjes. Het hangt ook af voor welke processor je compileert. Heeft de processor een instructie voor xor of niet en heeft de processor een instructie voor tilde?

Dat is vreemd; bij mij zie ik in beide gevallen exact dezelfde code.

De volgende C code:

c code:


unsigned char invert_1(unsigned char byte)
{
   unsigned char inv_byte = byte ^ 0xFF;

   return inv_byte; 
}

unsigned char invert_2(unsigned char byte)
{
   unsigned char inv_byte = ~byte;

   return inv_byte; 
}

Produceert met AVR GCC -O2:

avr asm code:

invert_1(unsigned char):
        com r24
ret
invert_2(unsigned char):
        com r24
ret

In het geval dat je XOR doet met 0xFF dan heeft met een 8-bits variabele ook een identiek effect als de tilde operator. Daarom is het ook niet zo vreemd is dat een optimizing C compiler(-O2 optie) in beide gevallen identieke output produceert.

Hier is een vrij obscure compiler die het verschillend doet.
Optimalisatie is uitgezet.

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Bovenstaande test is niet goed.
Volgende test is beter.
Hier dwing ik de compiler om in de eerste functie te xor-en.
Dat doe ik door te xor-en met 0xFE. Er is dan geen snellere route mogelijk
De tweede functie laat ik ongewijzigd en laat ik de compiler gewoon zijn werk doen. Optimalisatie is uitgeschakeld.
In de eerste functie zie je dat de instructie 'xor' aangeroepen wordt.
In de tweede functie zie je dat de instructie 'not' aangeroepen wordt.
Ook 'onder de motorkap' wordt hier de 'xor' en 'tilde' verschillend behandeld.
Dat hangt oa af van de mogelijkheden die de gebruikte processor biedt

Bezoek mijn neefjes' site: www.tinuselectronics.nl

De eerste processor is zo te zien een pic, de tweede een x86, die kun je niet met elkaar vergelijken.
De x86 heeft een veel complexere structuur.

Maar ongeacht de structuur, een XOR is een XOR en altijd snel.

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

Op 25 mei 2020 18:14:02 schreef ohm pi:
Bovenstaande test is niet goed.
Volgende test is beter.
Hier dwing ik de compiler om in de eerste functie te xor-en.
Dat doe ik door te xor-en met 0xFE. Er is dan geen snellere route mogelijk

Het probleem bij jouw test is dat XOR met 0xFE iets anders doet dan de tilde (~) operator. Het is dan ook niet meer dan logisch dat er andere machine code voor deze twee functies door de compiler gegenereerd wordt. Het is mij dan ook niet duidelijk wat jij nu met jouw test probeert te bewijzen.

De stelling was nu juist dat:

  1. Een XOR met 0xFF op een byte levert exact dezelfde uitkomst als de tilde operator op een byte; in beide gevallen worden alle bits in de byte geïnverteerd.
  2. Dat bij een goede compiler met optimalisaties ingeschakeld deze naar alle waarschijnlijkheid dezelfde machine code produceert voor inverteren van een byte ongeacht of dit nu gebeurt met ^0xFF of met de tilde operator.

Geen van deze stellingen worden weerlegt door jouw test.

@Arco ik heb op https://godbolt.org/z/A6a69_ geprobeerd met diverse processoren (AVR, x86, ARM ARM64, MIPS, MSP430, POWER64, RISC-V) en diverse compilers (GCC, CLANG, MSVC) in alle gevallen worden voor beide functies exact dezelfde machine code gegenereerd indien de optimizer (-O2) aanstaat. Omdat beide functies voor de bovenstaande stelling een identiek resultaat behoren te produceren, is het niet zo vreemd dat identieke machine code gegenereerd wordt - in dit geval is de instructie set van de processor niet zo relevant voor de bovenstaande stelling.

Op 25 mei 2020 22:57:02 schreef Patrick de Zeester:
[*]Dat bij een goede compiler met optimalisaties ingeschakeld deze naar alle waarschijnlijkheid dezelfde machine code produceert voor inverteren van een byte ongeacht of dit nu gebeurt met ^0xFF of met de tilde operator.

En... Dat met uitgeschakelde optimalisaties je vast bij de xor gewoon een xor met 0xff krijgt, maar na optimalisatie pas dezelfde code als een ~ operatie.

Ik heb:

c code:


unsigned char test1 (unsigned char t)
{
return ~t;
}

unsigned char test2 (unsigned char t)
{
return t^0xff;
}

unsigned char test3 (unsigned char t)
{
return 0xff-t;
}

met x86-64-gcc, AVR-gcc en met arm-gcc gecompileerd. Alledrie de functies leveren bij alle drie de compilers precies dezelfde code op. (na optimalisatie). Bij de arm-gcc compiler kan je zien dat het werken met de byte in de ARM tijd kost: Hij inverteert het hele 32 bit register en doet dan een AND met 0xff. De char vervangen door "int" en het scheelt een instructie!

[Bericht gewijzigd door rew op 25 mei 2020 23:18:59 (37%)]

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 25 mei 2020 22:57:02 schreef Patrick de Zeester:
Het is mij dan ook niet duidelijk wat jij nu met jouw test probeert te bewijzen.

Op 23 mei 2020 22:10:01 schreef Arco:
[...]
Met XOR ook, geen verschil... (wat dacht je dat die tilde 'onder de motorkap' doet?... ;) )

De stelling was dat de tilde 'onder de motorkap' omgezet wordt naar een XOR instructie.
Die stelling is met mijn voorbeeldcode ontkracht.
Alleen in de toevallige omstandigheid dat xor uitgevoerd wordt met 0xFF levert de compiler bij goed uitgevoerde optimalisatie dezelfde code op en meestal is dat de code die hoort bij de tilde.

[Bericht gewijzigd door ohm pi op 26 mei 2020 02:02:43 (15%)]

Bezoek mijn neefjes' site: www.tinuselectronics.nl

In de eerste instantie vertaalt de compiler

code:


  v = ~v;

in iets als

code:


  load v, r0
  com r0
  store r0, v

En voor

code:


  v = v ^ 0xff;

iets als

code:


   load v, r0
   load 0xff, r1
   exor r0, r1, r0
   store r0, v

Dit is zonder optimalisatie. Maar als er geoptimaliseerd moet worden dan ziet ie dat het resultaat precies hetzelfde is, en dat ie van deze sequences de kortste en snelste kan kiezen.

Laatst had ik een stukje test-code geschreven (voor CO). Ik telde steeds de loop variabele en de input parameter van de functie bij mekaar op. Bij optimalisatie bleek de functie samen te vatten tot return t*16+11; Niks loop. Dat had ie er allemaal uitgehaald. De optimalisatie is best goed.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/