Oder Ratschläge wie ich es noch verbessern/ verändern könnte.
C:
uint8_t index;
uint8_t length;
//index und length mit Werten füllen. (index 0 ist hier MSB, die Umkehrung ist aber nicht schwer)
assert(index + length < 8);
assert(index < 8);
assert(length > 0);
uint8_t mask = 0;
const int8_t shifter = (1 << 7); //0b10000000
uint8_t mask1 = (uint8_t)(shifter >> (index + length - 1));
uint8_t mask2 = (uint8_t)((shifter >> index) << 1);
mask = mask1 ^ mask2;
Einschränkungen:
1) two's-complement-system
2) Compiler mit arithmetischem shift
(Praktisch alle x86-CPUs und fast alle Chips sind so, einzige Ausnahme sind einige wenige Modems aus alten Zeiten und uralt-Maschinen)
Eine Erklärung dazu:
Wir nehmen shifter als ein signed-byte. D.h. der Wert, der zugewiesen wird (1 << 7), ist -128. Da das logische Shiften eine /2-Operation sein will, muss das auch auf negative Zahlen funktionieren (bzw. wurde einfach so definiert). Daher ist ein Shift von negativen Zahlen im two's-complement ein Shift, der das MSB kopiert:
C:
int8_t a = (1 << 7); //-128, 0b10000000
uint8_t b = (1 << 7); //128, 0b10000000
int8_t c = (1 << 6); //64, 0b01000000
// a >> 1 == -64 (0b11000000)
//b >> 1 == 64 (0b01000000)
//c >> 1 == 32 (0b00100000)
Code:
Am Beispiel von Index = 2, Length = 4: Wir erwarten 0b00111100
Nun macht der Code folgendes:
(shifter >> (index + length-1):
((1 << 7) >> (6-1)) == 0b11111100
Das ist nun mask1,
Dann müssen nur noch die ersten paar Bits aufgeräumt werden:
(shifter >> index) << 1:
((1 << 7) >> 2) << 1 == 0b11100000 << 1 == 0b11000000
Das ist mask2.
Als letztes noch XOR (gleiche Bits werden 0, ungleiche werden 1):
mask1 ^ mask2 ==
0b11111100 ^
0b11000000 ==
0b00111100
Meine Frage wäre jetzt ob ich das so umsetzen kann, ich erhalte jetzt ja jetzt meine Zahl für die "Bitmaske" aus meinen zwei eingegebenen Werten als Binärzahl.
Du bekommst zumindest keine Bitmaske, da du damit ja eigentlich nichts maskieren kannst (kein &).
Um aus deinem Array wieder eine Bitmaske zu basteln, ginge so etwas:
C:
uint8_t bitmask = 0;
for(size_t i = 0; i < 8; ++i)
bitmask |= (mask[i] & 1) << i)
Das ist eine andere Reihenfolge als in meinem Codevorschlag. Wenn du es umgekehrt haben willst:
uint8_t bitmask = 0;
for(size_t i = 0; i < 8; ++i)
bitmask |= (mask[7 - i] & 1) << i)
[/code]
Aber wie du ja selbst sehen kannst, ist mein Codevorschlag wesentlich kürzer (und das unoptimiert).
Es bietet sich gerade für C-Programmierer sehr an, die Bitoperationen im Schlaf zu können.
Hier noch eine bessere/direktere Version:
C:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
int main(int argc, char* argv[])
{
uint8_t index = 2;
uint8_t length = 0;
assert(index + length < 8);
assert(index < 8);
uint8_t mask = 0;
const int8_t shifter = (1 << 7); //0b10000000
uint8_t tmp = (shifter << (length == 0)) >> (length - (length != 0));
mask = tmp >> index;
printf("0b");
for(size_t i = 0; i < 8; ++i)
printf("%d", mask & (1 << (7-i)) ? 1 : 0);
return 0;
}
# Ops: 1 cmp, 1 shl, 1 sar, 1 shr, 1 sub, 2 sete (idealerweise, der Compiler hat natürlich anderes im Sinn...)
Wenn length als > 0 definiert ist, wird es sehr viel einfacher:
C:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
int main(int argc, char* argv[])
{
uint8_t index = 2;
uint8_t length = 0;
assert(index + length < 8);
assert(index < 8);
assert(length > 0);
uint8_t mask = 0;
const int8_t shifter = (1 << 7); //0b10000000
uint8_t tmp = shifter >> (length - 1);
mask = tmp >> index;
printf("0b");
for(size_t i = 0; i < 8; ++i)
printf("%d", mask & (1 << (7-i)) ? 1 : 0);
return 0;
}
//Als kleines Zückerchen, nur für mich: (ARMv6 assembly)
Code:
//r0: index
//r1: length
subs r1, #1
eorlt r0, r0 //Falls r1 - 1 negativ war (r1 war 0), setze r0 auf 0
blt lr //Beende, falls r1 0 war.
mvn r2, 0x7f, asr r1 //r2 = -128 >> r1
mov r0, r2, lsr r0
and r0, #0xFF
//resultat in r0, nun bx lr, falls in Funktion
(Ungetestet, sollte aber funktionieren. Man beachte die Schönheit von 6 Instruktionen (24 Bytes, 28 Bytes als Funktion)). Irgendetwas habe ich sicher übersehen; 1-3 Instruktionen könnten wohl gespart werden.
Diese Kürze bekommt man nur durch Bitoperationen selbst. Die char-Array-Variante dürfte ein Vielfaches davon kosten.
Gruss
cwriter
//Edit: Auch ein schöner Hack:
C:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
int main(int argc, char* argv[])
{
uint8_t index = 2;
uint8_t length = 0;
assert(index + length < 8);
assert(index < 8);
uint8_t mask = 0;
const uint16_t shifter = 0xFF00;
uint8_t tmp = shifter >> length; //Shifte nach rechts und kürze (truncate) auf 8 bits
mask = tmp >> index; //Shifte den Index
printf("0b");
for(size_t i = 0; i < 8; ++i)
printf("%d", mask & (1 << (7-i)) ? 1 : 0);
return 0;
}
Damit fallen alle Überprüfungen auf 0 und alle Arithmetischen Shifts weg und es ist noch ein bisschen übersichtlicher.