Es sei denn, Sie haben eine Maschine mit 15-Bit char
s, müssen Sie eine Menge von Bit-Manipulation, um Ihre 15-Bit-Werte über bis zu drei unsigned char
s mit Schichten und Bitmasken zu verbreiten.
Der folgende Code funktioniert für Maschinen mit CHAR_BIT
zwischen 8 und 15 einschließlich.
set15_le(mem, index, val)
mem
zeigt auf ein Feld von unsigned char
weist den Speicher für eine emulierte Array 15-Bit-Worte bereitstellt, ist index
der Index eines 15-Bit-Wort, und val
ist ein 15-Bit-Wert gespeichert werden. get15_le(mem, index)
gibt das 15-Bit-Wort aus dem angegebenen Index zurück. Die 15-Bit-Wörter werden in der Byte-Reihenfolge "Little-Endian" gespeichert.
set15_be(mem, index, val)
und get15_be(mem, index)
sind ähnlich wie oben, außer dass die 15-Bit-Wörter in "Big-Endian" Byte-Reihenfolge gespeichert werden.
Die Funktion main
testet beide Varianten, indem sie eine Gruppe von 15-Bit-Pseudozufallszahlen im Array speichert, sie liest und überprüft, ob sie den erwarteten Werten entsprechen.
#include <limits.h>
#if CHAR_BIT > 15
#error "Unsupported CHAR_BIT value"
#endif
unsigned short get15_le(const unsigned char *mem, unsigned long index)
{
unsigned long mem_index;
unsigned int mem_bitpos;
unsigned int val_bitpos;
unsigned short val_mask;
unsigned short val;
mem_index = (index * 15)/CHAR_BIT;
mem_bitpos = (index * 15) % CHAR_BIT;
val = 0;
val_bitpos = 0;
val_mask = (1U << 15) - 1;
while (val_mask)
{
unsigned int nbits;
unsigned char mem_mask;
unsigned char mem_byte;
nbits = CHAR_BIT - mem_bitpos;
if (nbits > 15 - val_bitpos)
{
nbits = 15 - val_bitpos;
}
mem_mask = val_mask << mem_bitpos;
mem_byte = mem[mem_index];
mem_byte &= mem_mask;
val |= (mem_byte >> mem_bitpos) << val_bitpos;
mem_bitpos += nbits;
if (mem_bitpos == CHAR_BIT)
{
mem_bitpos = 0;
mem_index++;
}
val_bitpos += nbits;
val_mask >>= nbits;
}
return val;
}
void set15_le(unsigned char *mem, unsigned long index, unsigned short val)
{
unsigned long mem_index;
unsigned int mem_bitpos;
unsigned int val_bitpos;
unsigned short val_mask;
mem_index = (index * 15)/CHAR_BIT;
mem_bitpos = (index * 15) % CHAR_BIT;
val_bitpos = 0;
val_mask = (1U << 15) - 1;
val &= val_mask;
while (val_mask)
{
unsigned int nbits;
unsigned char mem_mask;
unsigned char mem_byte;
nbits = CHAR_BIT - mem_bitpos;
if (nbits > 15 - val_bitpos)
{
nbits = 15 - val_bitpos;
}
mem_mask = val_mask << mem_bitpos;
mem_byte = mem[mem_index];
mem_byte &= ~mem_mask;
mem_byte |= ((val >> val_bitpos) << mem_bitpos) & mem_mask;
mem[mem_index] = mem_byte;
mem_bitpos += nbits;
if (mem_bitpos == CHAR_BIT)
{
mem_bitpos = 0;
mem_index++;
}
val_bitpos += nbits;
val_mask >>= nbits;
}
}
unsigned short get15_be(const unsigned char *mem, unsigned long index)
{
unsigned long mem_index;
unsigned int mem_bitpos;
unsigned int val_bitpos;
unsigned short val_mask;
unsigned short val;
mem_index = (index * 15)/CHAR_BIT;
mem_bitpos = CHAR_BIT - (index * 15) % CHAR_BIT;
val = 0;
val_bitpos = 15;
val_mask = (1U << 15) - 1;
while (val_mask)
{
unsigned int nbits;
unsigned char mem_mask;
unsigned char mem_byte;
nbits = mem_bitpos;
if (nbits > val_bitpos)
{
nbits = val_bitpos;
}
val_bitpos -= nbits;
mem_bitpos -= nbits;
mem_mask = (val_mask >> val_bitpos) << mem_bitpos;
mem_byte = mem[mem_index];
mem_byte &= mem_mask;
val |= (mem_byte >> mem_bitpos) << val_bitpos;
if (mem_bitpos == 0)
{
mem_bitpos = CHAR_BIT;
mem_index++;
}
val_mask >>= nbits;
}
return val;
}
void set15_be(unsigned char *mem, unsigned long index, unsigned short val)
{
unsigned long mem_index;
unsigned int mem_bitpos;
unsigned int val_bitpos;
unsigned short val_mask;
mem_index = (index * 15)/CHAR_BIT;
mem_bitpos = CHAR_BIT - (index * 15) % CHAR_BIT;
val_bitpos = 15;
val_mask = (1U << 15) - 1;
val &= val_mask;
while (val_mask)
{
unsigned int nbits;
unsigned char mem_mask;
unsigned char mem_byte;
nbits = mem_bitpos;
if (nbits > val_bitpos)
{
nbits = val_bitpos;
}
val_bitpos -= nbits;
mem_bitpos -= nbits;
mem_mask = (val_mask >> val_bitpos) << mem_bitpos;
mem_byte = mem[mem_index];
mem_byte &= ~mem_mask;
mem_byte |= ((val >> val_bitpos) << mem_bitpos) & mem_mask;
mem[mem_index] = mem_byte;
if (mem_bitpos == 0)
{
mem_bitpos = CHAR_BIT;
mem_index++;
}
val_mask >>= nbits;
}
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct mymemory
{
unsigned char content[(1000 * 15 + CHAR_BIT - 1)/CHAR_BIT];
};
int main(void)
{
struct mymemory mem;
unsigned long i;
unsigned short v;
printf("Memory size for 1000 15-bit words = %lu bytes (%lu bits)\n",
(unsigned long)sizeof(mem.content),
(unsigned long)sizeof(mem.content) * CHAR_BIT);
printf("Testing little-endian version\n");
memset(mem.content, 42, sizeof(mem.content));
srand(5);
for (i = 0; i < 1000; i++)
{
v = rand() & ((1U << 15) - 1);
set15_le(mem.content, i, v);
}
srand(5);
for (i = 0; i < 1000; i++)
{
unsigned int w;
v = rand() & ((1U << 15) - 1);
if ((w = get15_le(mem.content, i)) != v)
{
printf("Error at word %lu! got %u, expected %u\n", i, w, v);
break;
}
}
if (i == 1000)
{
printf("Passed!\n");
}
printf("Testing big-endian version\n");
memset(mem.content, 42, sizeof(mem.content));
srand(23);
for (i = 0; i < 1000; i++)
{
v = rand() & ((1U << 15) - 1);
set15_be(mem.content, i, v);
}
srand(23);
for (i = 0; i < 1000; i++)
{
unsigned int w;
v = rand() & ((1U << 15) - 1);
if ((w = get15_be(mem.content, i)) != v)
{
printf("Error at word %lu! got %u, expected %u\n", i, w, v);
break;
}
}
if (i == 1000)
{
printf("Passed!\n");
}
return 0;
}
Wenn Sie zu etwas anderem als Bytegrenzen packen wollen, vermute ich, dass Sie den Code schreiben müssen, um Verschiebung und Maskierung selbst vorzunehmen. – stark
Eine Struktur oder andere Objekte in C können nicht in der Mitte einer Byteadresse beginnen, da sie adressierbar sein müssen. Wenn das 1 Bit wirklich notwendig ist, packen Sie es anders, wie eine Struktur mit 15 'uint16_t' Elementen –
Sie werden wahrscheinlich ein Byte-Array der Größe 1875 verwenden müssen und es manuell in 15bit Chunks mit Shifting – user3853544