2017-02-17 10 views
1

Ich muss eine Speicherstruktur für ein Projekt erstellen, in dem jedes Wort 15 Bits umfasst. Wenn ich die Größe des Arrays überprüfe, bekomme ich, dass es 2000 Bytes groß ist, ich nehme an, dass es wegen der Compiler-Byte-Ausrichtung ist.15bit struct in C

Gibt es eine Möglichkeit, die Struktur zu erstellen, dass es 1875 Bytes groß sein wird?

Dies ist der Code, den ich verwendet:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#pragma pack(push,1) 
struct myword 
{ 
    unsigned int val : 15; 
}; 
struct mymemmory{ 

    struct myword arr[1000]; 
}; 
#pragma pack(pop) 


int main() 
{ 
    int size = sizeof(struct mymemmory); 
    printf("Size of arr: %d\n",size); 
    return 0; 
} 

Wenn ich #pragma pack(push,0) verwende ich bekommen, dass die Größe 4000 Byte.

+4

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

+1

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 –

+0

Sie werden wahrscheinlich ein Byte-Array der Größe 1875 verwenden müssen und es manuell in 15bit Chunks mit Shifting – user3853544

Antwort

1

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; 
} 
+0

Ich korrigierte die Packung von Bits in Zeichen für 'set15_be' und' get15_be', so dass wenn 15-Bit-Werte als von links nach rechts binäre geschrieben werden mit aufeinanderfolgenden Werten in der Reihenfolge von links nach rechts kann der Bitstrom in eine Folge von Zeichen in der Reihenfolge von links nach rechts aufgeteilt werden. –

2

Nein, gibt es nicht. Wenn Sie Bit-Level-Granularität benötigen, müssen Sie es selbst implementieren, indem Sie ein Array aus den 1875 Bytes erstellen und Indizes und Bitmasken manuell berechnen, um die gewünschten 15 Bits zu extrahieren. Wenn Sie vernünftig bleiben wollen, schließen Sie diese Funktionalität in Accessor-Funktionen aus, idealerweise mit C++ oder ähnlichem, wo Sie benutzerdefinierte Klassen erstellen können, die die Arbeit komplett abstrahieren (so einfache Indizierung verwendet alle "echten Index" und Bit-Verschiebung/Maske Arbeit hinter den Kulissen; std::vector<bool> macht schon so etwas für einzelne Bits).

Natürlich ist wahre Vernunft, dass es albern ist, über 125 Bytes zu quatschen. Es gibt sehr wenige Szenarien, in denen das Speichern eines Bits von sechzehn für jeden Wert (besonders für so wenige Werte) es wert ist, und diejenigen, die ich mir vorstellen kann (tatsächlich eine kompakte Darstellung auf der Festplatte benötigend), werden noch besser durch Konvertieren von der CD gehandhabt Repräsentation in der erweiterten Speicherdarstellung beim Lesen und beim Schreiben zurückkonvertiert, um den Aufwand und den Rechenaufwand beim Umgang mit dem Verschieben und Maskieren bei jedem Lesen/Schreiben zu vermeiden.

+0

Danke für die detaillierte Antwort –