簡體   English   中英

將無符號16位整數存儲到文件的最有效方法

[英]Most efficient way to store an unsigned 16-bit Integer to a file

我正在用C制作字典壓縮器,字典最大大小為64000。因此,我將條目存儲為16位整數。

我目前正在做什么:要編碼“ a”,我要得到其ASCII值97,然后將此數字轉換為16位整數97的字符串表示形式。因此我最終為“ a”編碼了“ 0000000001100001” ”,這顯然在短期內不會節省太多空間。

我知道此算法的更有效版本將從較小的整數大小開始(較少的存儲位,直到我們需要更多位)開始,但是我想知道是否有更好的方法可以

  1. 將我的整數'97'轉換為固定長度的ASCII字符串,該字符串可以存儲16位數據(97將是x位,46347也將是x位)

  2. 寫入只能存儲1和0的文件。 因為實際上是在向文本文件寫入16個ascii字符,每個字符都是8位...所以這實際上並沒有太大幫助,不是嗎?

請以任何方式讓我更加清晰。 我是這個網站的新手。 謝謝!

編輯:據我所知,我如何存儲字典完全取決於我。 我只知道我需要能夠輕松地讀回編碼的文件並從中獲取整數。

另外,我只能包含為該程序編寫的stdio.h,stdlib.h,string.h和頭文件。

請不要理會那些建議您“直接寫入文件”的人。 與此相關的問題很多,最終都屬於“整數表示”類別。 使用fwrite或what-not將整數直接寫到外部存儲中似乎有一些令人信服的原因,這里有一些可靠的事實。

瓶頸是外部存儲控制器。 如果要編寫網絡應用程序,則為網絡,否則為網絡。 因此,如果您的內存配置文件適合您的平台,那么將兩個字節作為單個fwrite或作為兩個不同的fputc寫入應該大致相同的速度。 您可以使用setvbufFILE *的緩沖區使用量調整到一定程度(注意:必須為2的冪),因此我們總是可以根據分析器告訴我們的每個平台進行微調,盡管此信息應可能會通過溫和的建議優雅地向標准庫上游浮動,從而對其他項目也有用

當今的計算機之間底層的整數表示形式是不一致的。 假設您使用系統X將unsigned int直接寫入文件,該系統使用32位int和大端序表示,那么在系統Y上讀取該文件時會遇到問題,該系統使用16位int和小端序表示或系統Z使用具有混合字節序表示形式的64位整數和32個填充位。 如今,我們混合使用了15年前的計算機,人們大受ARM的折磨。很少有SoC,智能手機和智能電視,游戲機和PC,它們都有自己的怪癖,不屬於標准C領域,特別是關於整數表示,填充等。

C的開發考慮到了抽象性,使您可以輕便地表達算法,從而不必為每個操作系統編寫不同的代碼! 這是一個將四個十六進制數字讀取並轉換為unsigned int值的示例,可移植:

unsigned int value;
int value_is_valid = fscanf(fd, "%04x", &value) == 1;
assert(value_is_valid); // #include <assert.h>
                        /* NOTE: Actual error correction should occur in place of that
                         *       assertioon
                         */

我應該指出為什么選擇%04X而不選擇%04X %08X或更現代的東西的原因...如果直到今天我們仍然提出一些問題, 不幸的是有些學生使用的教科書和編譯器已經有20多年的歷史了...他們的int是16位的,而且從技術上講,他們的編譯器在這方面是兼容的(盡管他們確實應該在整個學術界推廣gcc和llvm)。 考慮到可移植性,這是我如何編寫該值的方法:

value &= 0xFFFF;
fprintf(fd, "%04x", value);
// side-note: We often don't check the return value of `fprintf`, but it can also become   \
              very important, particularly when dealing with streams and large files...

假設您的unsigned int值占據兩個字節,這是我使用大端字節表示法可移植地讀取這兩個字節的方法:

int hi = fgetc(fd);
int lo = fgetc(fd);
unsigned int value = 0;
assert(hi >= 0 && lo >= 0); // again, proper error detection & handling logic should be here
value += hi & 0xFF; value <<= 8;
value += lo & 0xFF;

...這就是我按照大端順序寫入這兩個字節的方法:

fputc((value >> 8) & 0xFF, fd);
fputc(value & 0xFF, fd);
// and you might also want to check this return value (perhaps in a finely tuned end product)

也許您對Little Endian更感興趣。 整潔的是,代碼確實沒有什么不同。 輸入如下:

int lo = fgetc(fd);
int hi = fgetc(fd);
unsigned int value = 0;
assert(hi >= 0 && lo >= 0);
value += hi & 0xFF; value <<= 8;
value += lo & 0xFF;

...這是輸出:

fputc(value & 0xFF, fd);
fputc((value >> 8) & 0xFF, fd);

對於大於兩個字節的任何內容(即, long unsignedlong signed ),您可能想要fwrite((char unsigned[]){ value >> 24, value >> 16, value >> 8, value }, 1, 4, fd); 或例如減少樣板的東西。 考慮到這一點,形成預處理器宏似乎並不濫用:

#define write(fd, ...) fwrite((char unsigned){ __VA_ARGS__ }, 1, sizeof ((char unsigned) { __VA_ARGS__ }), fd)

我想一個人可能會這樣看,就像選擇以下兩個弊端中的更好者一樣:預處理程序濫用或上面代碼中的幻數4 ,因為現在我們可以write(fd, value >> 24, value >> 16, value >> 8, value); 沒有對4進行硬編碼...但是一個不為人所知的詞: 副作用可能會引起頭痛,因此請不要在write參數中引起任何形式的修改,寫入或全局狀態更改。

好吧,這是我今天對此信息的更新...社交延遲的怪胎人員現在退出。

您正在考慮的是利用ASCII字符保存數字,這完全沒有必要,而且效率最低。

最節省空間的方法(不使用復雜算法)是將數字的字節轉儲到文件中(位數必須取決於您要保存的最大數字,或者具有多個文件用於8位,16位等

然后,當您讀取文件時,您就會知道數字位於每x個位數中,因此只需將它們逐個或大塊地讀出,然后將大塊分成一個類型的數組即可匹配x#位。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM