「ファイルに直接書き込む」ことを提案しているこれらの人々を無視してください。これには多くの問題があり、最終的には「整数表現」のカテゴリに分類されます。整数を外部ストレージに直接書き込むfwrite
かどうかには、いくつかの説得力のある理由があるようです。ここでは、いくつかの確かな事実があります。
ボトルネックは外部ストレージコントローラーです。それ、またはネットワークアプリケーションを作成している場合はネットワーク。したがって、2バイトを単一fwrite
または2つの別個fputc
のとして書き込むことは、メモリプロファイルがプラットフォームに適切であれば、ほぼ同じ速度である必要があります。FILE *
を使用して、使用するバッファーの量をある程度調整できますsetvbuf
(注:2の累乗である必要があります)。したがって、プロファイラーの指示に基づいてプラットフォームごとに常に微調整できますが、この情報はおそらく適切にフロートするはずです。他のプロジェクトにも役立つ穏やかな提案を通じて、標準ライブラリの上流にあります。
基礎となる整数表現は、今日のコンピューター間で一貫性がありません。32ビットintとビッグエンディアン表現を使用するシステムXを使用してファイルに直接sを書き込むとするとunsigned int
、16ビットintとリトルエンディアン表現を使用するシステムY、またはシステムZでそのファイルを読み取る際に問題が発生します。混合エンディアン表現と32パディングビットを備えた64ビットintを使用します。今日では、15年前のこのようなコンピューターの組み合わせがあり、人々はARM big.Little SoC、スマートフォン、スマートTV、ゲーム機、PCに苦しんでいます。これらはすべて、標準Cの領域から外れた独自の癖を持っています。特に整数表現、パディングなどに関して。
Cは、アルゴリズムを移植可能に表現できるようにする抽象化を念頭に置いて開発されたため、OSごとに異なるコードを記述する必要はありません。unsigned int
これは、4桁の16進数を読み取って値に変換する例です。
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
私が選んだ理由と、もっと現代的なものを選んだ理由を指摘する必要があります%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...
値が2バイトを占めると仮定するとunsigned int
、ビッグエンディアン表現を使用して、これらの2バイトを移植可能に読み取る方法は次のとおりです。
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;
...そして、これらの2バイトをビッグエンディアンの順序で書き込む方法は次のとおりです。
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)
おそらく、あなたはリトルエンディアンにもっと興味があります。きちんとしたことは、コードは実際にはそれほど違いはないということです。入力は次のとおりです。
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);
2バイトを超えるもの(つまり、along unsigned
またはlong 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
。
さて、それはその日のこの投稿への私の更新です...社会的に遅れたオタクの人は今のところサインアウトしています。