時々、SO=の誰かが char
(別名 'byte')は必ずしも8ビットではない と指摘しています。
8ビットchar
はほぼ普遍的であるようです。主流のプラットフォームでは、市場での実行可能性を確保するために8ビットのchar
が必要だと思っていたでしょう。
現在も歴史的にも、どのプラットフォームが8ビットではないchar
を使用しており、なぜそれらが「通常の」8ビットと異なるのでしょうか?
コードを記述し、クロスプラットフォームサポート(たとえば、汎用ライブラリ)について考えるとき、8ビット以外のchar
を備えたプラットフォームにどのような考慮を払う価値がありますか?
過去に、char
が16ビットであるいくつかのAnalog Devices DSPに出会いました。 DSPは、私が思うにちょっとしたニッチなアーキテクチャです。 (そのときも、手作業でコーディングされたアセンブラは、利用可能なCコンパイラでできることを簡単に打ち負かしたので、そのプラットフォームでのCの経験はあまりありませんでした。)
char
は、Texas Instruments C54x DSPでも16ビットであり、たとえばOMAP2で見つかりました。 16ビットと32ビットのchar
を持つ他のDSPがあります。 24ビットDSPについても聞いたことがあると思いますが、何を思い出せないので、想像したかもしれません。
もう1つの考慮事項は、POSIXがCHAR_BIT == 8
を義務付けていることです。したがって、POSIXを使用している場合は、それを想定できます。後で誰かがコードをPOSIXの実装に近いものに移植する必要がある場合、使用している関数が異なるサイズchar
になっているのは偶然です。
ただし、一般的には、問題を考えるよりも、問題を回避する方がほとんど常に簡単だと思います。 CHAR_BIT
と入力するだけです。正確な8ビットタイプが必要な場合は、int8_t
を使用します。コードは、予期しないサイズを静かに使用する代わりに、提供しない実装で騒々しくコンパイルできません。少なくとも、私がそれを仮定する正当な理由があったケースを見つけた場合、私はそれを主張するでしょう。
コードを記述し、クロスプラットフォームサポート(たとえば、汎用ライブラリ)を検討する場合、8ビット以外の文字を持つプラットフォームにどのような考慮を払う価値がありますか?
ルールに従ってプレイしているので、何かを「考慮する価値がある」ほどではありません。たとえば、C++では、標準ではすべてのバイトに「少なくとも」8ビットが含まれるとされています。バイトが正確に8ビットであるとコードが想定している場合、標準に違反しています。
これは今ではばかげているように見えるかもしれません-「もちろんすべてのバイトは8ビットです!」しかし、非常に賢い人の多くは、保証ではない仮定に依存しており、すべてが壊れました。このような例は歴史に満ちています。
たとえば、90年代前半のほとんどの開発者は、ほとんどのコンシューマCPUの電力はほぼ同等であったため、特定のno-op CPUタイミング遅延に固定サイクル数を要すると固定クロック時間を要すると想定していました。残念ながら、コンピューターは非常に高速になりました。これにより、「ターボ」ボタンを備えたボックスが台頭しました。その目的は、皮肉なことに、時間遅延技術を使用したゲームを妥当な速度でプレイできるようにコンピューターの速度を落とすことでした。
あるコメンターは、標準ではcharには少なくとも8ビットが必要だと言っています。セクション5.2.4.2.1にあります。このセクションでは、CHAR_BIT
(最小のアドレス指定可能なエンティティのビット数)を定義し、デフォルト値は8です。
それらの実装定義の値は、同じ符号で示されたものと同じかそれ以上の大きさ(絶対値)でなければなりません。
したがって、8以上の任意の数は、CHAR_BIT
への実装による置換に適しています。
36ビットアーキテクチャのマシンには9ビットバイトがあります。ウィキペディアによると、 6ビットアーキテクチャのマシン は次のとおりです。
私が知っているいくつか:
完全に移植可能なコードなどはありません。 :-)
はい、さまざまなバイト/文字サイズがあります。はい、非常に珍しいCHAR_BIT
およびUCHAR_MAX
の値を持つプラットフォーム用のC/C++実装があるかもしれません。はい、文字サイズに依存しないコードを作成できる場合があります。
ただし、ほとんどの実際のコードはスタンドアロンではありません。例えば。ネットワークにバイナリメッセージを送信するコードを書いているかもしれません(プロトコルは重要ではありません)。必要なフィールドを含む構造を定義できます。シリアル化する必要があるよりも。構造体を出力バッファーにバイナリコピーするだけでは移植性がありません。一般に、プラットフォームのバイトオーダーも構造体メンバーのアライメントもわからないため、構造体はデータを保持するだけで、データのシリアル化方法は説明しません。 。
OK。 memcpy
を使用して、バイトオーダー変換を実行し、構造メンバー(たとえば、uint32_t
または同様のもの)をバッファーに移動できます。なぜmemcpy
?ターゲットアドレスが適切にアライメントされていない場合、32ビット(16ビット、64ビット-差なし)を書き込むことができないプラットフォームが多数あるためです。
したがって、移植性を実現するためにすでに多くのことを行っています。
そして最後の質問です。バッファがあります。それからのデータはTCP/IPネットワークに送信されます。このようなネットワークは、8ビットバイトを想定しています。質問は次のとおりです。どのタイプのバッファが必要ですか?あなたの文字が9ビットなら? 16ビットの場合は? 24?たぶん、各文字はネットワークに送信された1つの8ビットバイトに対応し、8ビットのみが使用されますか?それとも、複数のネットワークバイトが24/16/9ビットの文字にパックされているのでしょうか?それは質問であり、すべての場合に当てはまる単一の答えがあるとは信じられません。多くのことが、ターゲットプラットフォームのソケット実装に依存しています。
だから、私が話していること。通常、コードはある程度簡単に移植可能です。異なるプラットフォームでコードを使用する場合は、そうすることが非常に重要です。ただし、その測定値を超えて移植性を改善することは、多くの労力を必要とし、多くの場合ほとんどを与えるものです。上記の例のソケット実装)。 8ビットにバインドされた環境を使用するため、コードの約90%で8ビット以外のバイトを持つプラットフォームで動作する能力はほとんど役に立たないと確信しています。バイトサイズを確認し、コンパイル時間のアサーションを実行するだけです。ほぼ間違いなく、非常に珍しいプラットフォームのために多くを書き直す必要があります。
しかし、コードが高度に「スタンドアロン」である場合-なぜですか?異なるバイトサイズを許可する方法で記述できます。
多くのDSPチップには、16ビットまたは32ビットのchar
があります。 TIはこのようなチップを定期的に作成します たとえば 。
IM6100を購入する (つまり、チップ上のPDP-8)を倉庫から出すことができるようです。これは12ビットアーキテクチャです。
たとえば、CおよびC++プログラミング言語は、バイトを「実行環境の基本文字セットのメンバーを保持するのに十分な大きさのアドレス可能なデータ単位」として定義します(C標準の3.6節)。 C char整数データ型には少なくとも8ビットが含まれている必要があるため(5.2.4.2.1節)、Cのバイトは少なくとも256の異なる値を保持できます。 CおよびC++のさまざまな実装は、バイトを8、9、16、32、または36ビットとして定義します
http://en.wikipedia.org/wiki/Byte#History から引用
ただし、他の言語についてはわかりません。
http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats
そのマシン上のバイトを可変長に定義します
DEC PDP-8ファミリには12ビットのWordがありましたが、通常は出力に8ビットASCII=を使用しました(Teletypeでのほとんど))。ただし、6ビット文字コードを使用すると1つの12ビットWordで2文字をエンコードします。
1つは、Unicode文字が8ビットより長いことです。誰かが先に述べたように、C仕様は最小サイズによってデータ型を定義します。データ型を調べて、構成とアーキテクチャに適したサイズを正確に検出する場合は、sizeof
とlimits.h
の値を使用します。
このため、特定のビット長のデータ型が必要な場合は、uint16_t
などのデータ型に固執しようとします。
編集:申し訳ありませんが、最初は質問を読み間違えました。
Cの仕様では、char
オブジェクトは「実行文字セットのメンバーを格納するのに十分な大きさ」であるとされています。 limits.h
は8ビットの最小サイズをリストしますが、定義はchar
の最大サイズを開いたままにします。
したがって、a char
は、少なくともアーキテクチャの実行セットの最大文字(通常、最も近い8ビット境界に切り上げられます)と同じ長さです。アーキテクチャのオペコードが長い場合、char
サイズが長くなる可能性があります。
歴史的に、x86プラットフォームのオペコードは1バイト長であったため、char
は最初は8ビット値でした。現在のx86プラットフォームは1バイトより長いオペコードをサポートしていますが、char
はプログラマ(および既存のx86コードの大部分)の条件であるため、8ビットの長さに維持されます。
マルチプラットフォームのサポートについて考えるときは、stdint.h
で定義されている型を利用してください。 (たとえば)uint16_tを使用する場合、その値がchar
、short
、または他の何か。ほとんどのハードワークは、コンパイラ/標準ライブラリを書いた人々によってすでに行われています。
int
を必要とする低レベルのハードウェア操作を行っているためにchar
の正確なサイズを知る必要がある場合、通常、char
を保持するのに十分な大きさのデータ型を使用しますサポートされているすべてのプラットフォーム(通常は16ビットで十分です)で、正確なマシン表現が必要なときにconvert_to_machine_char
ルーチンを介して値を実行します。そうすれば、プラットフォーム固有のコードはインターフェイス関数に限定され、ほとんどの場合、通常のuint16_t
を使用できます。
8ビット文字以外のプラットフォームでは、どのような考慮事項がありますか?
マジックナンバーが発生しますシフトするとき;
これらのほとんどは、CHAR_BITと8および255(または同様)の代わりにUCHAR_MAX。
うまくいけば、あなたの実装がそれらを定義します:)
これらは「一般的な」問題です。
別の間接的な問題は、あなたが持っていると言うことです:
struct xyz {
uchar baz;
uchar blah;
uchar buzz;
}
これは、1つのプラットフォームで「最高」の24ビットしか使用しない場合がありますが、他の72ビット.....
各ucharが「ビットフラグ」を保持し、各ucharに現在使用している2つの「重要な」ビットまたはフラグがあり、それらを「明瞭」のために3つのucharのみに編成した場合、比較的「無駄」です。 24ビットucharsを備えたプラットフォーム上で.....
ビットフィールドでは解決できないものはありませんが、他にも注意すべき点があります。
この場合、実際に必要な「最小」サイズの整数を取得する方法は、単一の列挙型だけです。
おそらく実際の例ではないかもしれませんが、このようなものは、いくつかのコードを移植/再生するときに「ビット」です。
ucharが「通常」の期待値の3倍の大きさである場合、そのような構造の100個は、一部のプラットフォームで大量のメモリを浪費する可能性があります。 。
したがって、1つのプラットフォームでRAMに比べてucharが「あまり無駄ではない」という仮定のために、物事は依然として「壊れている」か、この場合「非常に速くメモリを浪費します」他のプラットフォームよりも利用可能.....
問題はより顕著かもしれません。 int、または他のタイプ、例えばあなたは15ビットを必要とする構造を持っているので、それをintに固定しますが、他のプラットフォームではintは48ビットか何かです.....
「通常」それを2つのucharに分割できますが、 24ビットのucharでは、必要なのは1つだけです。
したがって、列挙型の方が「一般的な」解決策になる可能性があります。
ただし、これらのビットにアクセスする方法によって異なります:)
そのため、コードがucharまたはuintのサイズに関係なく正常に動作/実行される場合でも、頭を支える「設計上の欠陥」があるかもしれません...
コードには「マジックナンバー」はありませんが、このような注意が必要です...
これが理にかなっていることを望みます:)
以前は16ビットであったint(pdp11など)。 32ビットアーキテクチャに移行するのは困難でした。人々は良くなっています:ポインターがこれ以上長く収まると思い込んでいる人はほとんどいません(そうではありませんか?)。またはファイルオフセット、またはタイムスタンプ、または...
8ビット文字は、すでに多少時代錯誤です。世界のすべての文字セットを保持するには、すでに32ビットが必要です。