Nedávno jsem začal čistit své projekty a rozhodl jsem se, že chci vytvořit osobní úložiště užitečných bitů kódu. Našel jsem mezi nimi tento bitmapový kód a těžce jej upravil a ocenil bych, kdyby ho někdo mohl zkontrolovat, protože nejsem zvyklý na bitové operace a podobně. Je kód dostatečně přenosný, nebo by mělo dojít ke změnám?
bitmap.h
#ifndef BITMAP__ #define BITMAP__ #define BIT (8*sizeof(byte)) #define BITMAP_NOTFOUND -1 typedef enum{false=0, true} bool; typedef unsigned char byte; bool bitmapGet (byte *, int); void bitmapSet (byte *, int); void bitmapReset (byte *, int); int bitmapSearch(byte *, bool, int, int); #endif
bitmap.c
#include "bitmap.h" static bool get (byte, byte); static void set (byte *, byte); static void reset(byte *, byte); /* CAREFUL WITH pos AND BITMAP SIZE! */ bool bitmapGet(byte *bitmap, int pos) { /* gets the value of the bit at pos */ return get(bitmap[pos/BIT], pos%BIT); } void bitmapSet(byte *bitmap, int pos) { /* sets bit at pos to 1 */ set(&bitmap[pos/BIT], pos%BIT); } void bitmapReset(byte *bitmap, int pos) { /* sets bit at pos to 0 */ reset(&bitmap[pos/BIT], pos%BIT); } int bitmapSearch(byte *bitmap, bool n, int size, int start) { /* Finds the first n value in bitmap after start */ /* size is the Bitmap size in bytes */ int i; /* size is now the Bitmap size in bits */ for(i = start+1, size *= BIT; i < size; i++) if(bitmapGet(bitmap,i) == n) return i; return BITMAP_NOTFOUND; } static bool get(byte a, byte pos) { /* pos is something from 0 to 7*/ return (a >> pos) & 1; } static void set(byte *a, byte pos) { /* pos is something from 0 to 7*/ /* sets bit to 1 */ *a |= 1 << pos; } static void reset(byte *a, byte pos) { /* pos is something from 0 to 7*/ /* sets bit to 0 */ *a &= ~(1 << pos); }
Komentáře
- Každému, kdo tento příspěvek stále sleduje, jsem zavázal kód github sem . Také jsem přidal všechny vaše komentáře jako problémy. Děkujeme za vaše komentáře a začnu je implementovat.
Odpovědět
Pokud očekáváte, že váš kód někdy bude použitý z C ++ (což je hodně C kódu), pak byste neměli používat žádné identifikátory s dvojitým podtržítkem.
#ifndef BITMAP__ // ^^ May cause problems in C++
Protože je to vyhrazeno pro implementaci v C ++. Termín BITMAP je také velmi obecný a je velmi pravděpodobné, že se střetnete s jinými knihovnami, a zkuste jej udělat pro svůj projekt jedinečnějším.
Předpokládáte, že znak má 8 bitů.
#define BIT (8*sizeof(byte))
Standard to neříká (má minimálně 8 bitů), ale ve skutečnosti je definován prostřednictvím makra CHAR_BITS, takže byste měli použít:
#define BIT (CHAR_BITS*sizeof(byte))
Váš záhlaví souboru je to, jak většina lidí nejprve uvidí váš kód a pokusí se pochopit, jak jej používat. Vkládání názvů parametrů do souboru záhlaví je tedy pravděpodobně dobrý nápad, protože pomáhá dokumentovat jejich použití.
bool bitmapGet (byte *, int); void bitmapSet (byte *, int); void bitmapReset (byte *, int); int bitmapSearch(byte *, bool, int, int);
Další akce není zřejmé, takže komentář k jeho použití v záhlaví by byl pravděpodobně dobrý nápad. Ve skutečnosti by malá reklama o tom, jak může být prvním parametrem pole, pravděpodobně dobrý nápad (protože bez přečtení kódu to není zřejmé).
Buďte opatrní s komentáři:
/* pos is something from 0 to 7*/
To platí pouze v případě, že vytvoříte předpoklady (A: that sizeof (byte) == 1 B: vynásobíte to 8). Komentář měl být:
/* pos is a value between [0, BIT) */
Všimněte si použití „[“ vlevo a „)“ vpravo. Jedná se o matematický zápis, který naznačuje, že 0 je inkluzivní a BIT není zahrnut v rozsahu (je to běžné v dokumentaci C / C ++).
Odpověď
-
Vaše typy jsou zbytečné – stačí použít nepodepsaný char a int jako standardní knihovna.
-
Na stejné téma je vaše enum bool zbytečné, protože v C nenulová označuje skutečný stav. Potvrzujete to sami, protože get () předpokládá, že hodnota 1 je true. Každý to předpokládá, a proto je typ nadbytečný. Navíc je to také špatné, protože pokud změním váš výčet na
typedef enum{true=0, false} bool;
vaše funkce selže, i když je logicky rozumné to udělat.
Pokud chcete použít takový bool, měli byste explicitně vrátit jednu z jeho hodnot:
return ((a >> pos) & 1) ? true : false;
, ale v tomto opravdu nemá smysl. Stačí vrátit int jako standardní knihovna.
-
bitmapGet () vrací bool se mi zdá chybně pojmenovaný. Bitmapové bity mají hodnoty 1 a 0, nejsou pravdivé a nepravdivé (i když jsou aktuálně stejné). Nazvat to bitmapIsSet () by bylo logičtější.
-
sizeof (char) je podle definice 1, takže BIT lze nahradit CHAR_BIT
-
Otevírací závorky pro funkce jsou obvykle ve sloupci 0
-
Pořadí parametrů pro bitmapové vyhledávání by bylo logičtější, pokud jde o velikost, po které následuje věc, na kterou odkazuje (bitmapa).
-
Počáteční parametr pro bitmapové vyhledávání je špatný. Chcete-li zadat vyhledávání začínající od bitu 0 (určitě nejběžnějšího), musí volající předat -1 !!
-
Proč předávat parametr „pos“ jako „bajt“? Definovali jste „byte“, který představuje bitmapové bajty, a „pos“ rozhodně není jedním z nich. Zobrazí se upozornění kompilátoru, pokud jsou povolena (měla by být) ohledně předávání argumentů s různými šířkami kvůli prototypům. A omezení „pos“ na bajt může přidat další strojovou instrukci (podívejte se na assembler), zatímco nic nedosáhnete. Pokud byste mohli definovat typ pos_t s rozsahem 0..7, který se zdá, že chcete, pak byste mohli tvrdit, že to bylo nějakým způsobem správné, ale protože to nemůžete udělat v C a jednoznačně má bajtová hodnota rozsah 0 .. 255, není to o nic lepší než použít int.
Odpovědět
Nedělat to zeptejte se na výkon, ale můžete bitmapSearch
pro řídké bitmapy zrychlit tak, že se nejprve podíváte po bajtech najednou. Pokud hledáte 1, můžete přeskočit bajty o velikosti 0x00 a pokud hledáním 0 můžete přeskočit bajty, které jsou 0xFF. Poté můžete naskenovat bity dalšího bytu nebo použít vyhledávací tabulku.
Pokud jde o rozhraní API, můžete přidat
byte * bitmapAlloc(int sizeInBits); void bitmapFree(byte * bitmap);
, aby si klient nemusel dělat starosti s počtem bytů přidělit.
A / nebo poskytnout makro, které vám pomůže s přidělením. Makro místo funkce, pokud chcete, aby se zobrazovalo v přidělování polí.
#define BITMAP_BYTE_COUNT_FOR(n) ((n)+BIT-1)/BIT)
Já také bitmapSearch
vezmu jeho velikost jako počet bitů místo počtu bajtů. Pokud se pak klient stará pouze o 26 bitů pro písmena, nemusí se bát, že vyhledávání vrátí 27, protože bitmapa má ve skutečnosti 32 bitů.