53


21

バイトのバッファはsigned charかunsigned charのどちらか、あるいは単にcharバッファなのか。 CとCの違いは何ですか?

ありがとう。

14 回答


47


任意のバイナリデータを保存するつもりなら、 unsigned char`を使うべきです。 C規格でパディングビットがないことが保証されているのは、これが唯一のデータ型です。 他の各データ型は、そのオブジェクト表現にパディングビットを含めることができます(つまり、値を決定するものだけではなく、オブジェクトのすべてのビットを含むものです)。 パディングビットの状態は指定されていないため、値の格納には使用されません。 ですから、バイナリデータを `char`を使って読む場合、(値のビットだけを解釈することによって)charの値の範囲に切り捨てられますが、無視されるだけのビットがまだ存在する可能性があります。 `memcpy。 実際の構造体オブジェクトにビットを埋め込むのとよく似ています。 unsigned char型はそれらを含まないことが保証されています。 それは `5.2.4.2.1 / 2 '(C99 TC2、ここではn1124)から続きます:

_ 式で使用されるときにchar型のオブジェクトの値が符号付き整数として扱われる場合、「CHAR_MIN」の値は「SCHAR_MIN」の値と同じになり、「CHAR_MAX」の値はそれと同じになります「SCHAR_MAX」の。 そうでなければ、「CHAR_MIN」の値は0になり、「CHAR_MAX」の値は「UCHAR_MAX」の値と同じになります。 _値「UCHAR_MAX」は「2 ^ CHAR_BIT − 1」に等しくなければなりません __

最後の文から、パディングビット用のスペースが残っていないことがわかります。 バッファの型として char`を使うと、オーバーフローの問題もあります: 8`ビットの範囲内にあるそのような要素に明示的に値を代入する - そのような代入は問題ないと思うかもしれません - しかし、 CHAR_MIN..CHAR_MAXである char`の範囲内では、このような変換はオーバーフローし、シグナルの発生を含む実装定義の結果を引き起こします。

上記の問題が実際の実装ではおそらく表示されないかもしれないとしても(非常に貧弱な実装品質になるでしょう)、最初から正しい型、つまり `unsigned char`を使うのが最善です。

しかしながら、文字列の場合、選択するデータ型は `char`です。これは文字列と印刷関数によって理解されます。 これらの目的で `signed char`を使うことは私にとって間違った決断のように見えます。

より詳しい情報はhttp://www.open-std.org/jtc1/sc22/wg14/www/docs/n1310.htm [この提案]を読んでください。 `signed char`にはパディングビットも必要としません。 それはすでにhttp://www.open-std.org/JTC1/SC22/WG14/www/docs/n1362.pdf [Working paper]に組み込まれています。


31


_ バイトのバッファはsigned charかunsigned charのどちらか、あるいは単にcharバッファなのか。 CとCの違いは何ですか? _

言語がそれをどのように扱うかにおける小さな違い。 慣習がそれを扱う方法の*大きな*違い。

  • char = ASCII(またはUTF-8、ただし符号付きが邪魔になる) *テキスト*データ

  • unsigned char = byte

  • signed char =めったに使われない

そして、そのような区別に頼るコードがあります。 ほんの1〜2週間前に、Base 64エンコード関数の char *`バージョンに渡されていたためにJPEGデータが破損していたというバグに遭遇しました。 。 それを修正するために必要だったのは、 `unsigned char`とも呼ばれる BYTE`への変更です。


12


場合によります。

バッファがテキストを保持することを意図している場合、おそらくそれを `char`の配列として宣言し、それがデフォルトで符号付きか符号なしかをプラットフォームに判断させるのが理にかなっています。 たとえば、実装のランタイムライブラリとの間でデータをやり取りするのが最も簡単になります。

バッファがバイナリデータを保持することを目的としている場合、それはあなたがそれをどのように使用するつもりであるかによって異なります。 例えば、バイナリデータが実際に符号付き8ビット固定小数点ADC測定値のパックされたデータサンプルの配列である場合、「signed char」が最適になります。

実際のほとんどの場合、バッファはそれだけのバッファです。バッファを一括操作で埋めているため、個々のバイトの種類についてはあまり気にする必要はありません。複雑なデータ構造を解釈して何か有用なことをするパーサ。 その場合は、最も簡単な方法で宣言してください。


9


もしそれが実際にマシンのデフォルトロケールの文字列ではなく8ビットバイトのバッファであれば、私は `uint8_t`を使います。 charがバイト(またはバイトはオクテット)ではないところに多くのマシンがあるというわけではありませんが、「これは文字列です」ではなく「これはオクテットのバッファです」というステートメントを作成すると便利なドキュメントです。


5


_char_または_unsigned char_を使用する必要がありますが、_signed char_は使用しないでください。 規格は3.9 / 2で以下の通りです

_ PODタイプTのオブジェクト(ベースクラスサブオブジェクト以外)の場合、オブジェクトがタイプTの有効な値を保持しているかどうかに関係なく、オブジェクトを構成する基本バイト(1.7)をcharまたはunsignedの配列にコピーできますchar.charまたはunsigned charの配列の内容がオブジェクトにコピーされた場合、オブジェクトは元の値を保持します。 _


4


unsigned charとして定義した方が良いでしょう。 事実上のWin32型BYTEはunsigned charとして定義されています。 Cに違いはありません


3


最大限の移植性のために、常にunsigned charを使用してください。 これがうまくいく可能性がある事例がいくつかあります。 異なるエンディアンタイプを持つシステム間で共有されるシリアル化されたデータはすぐに頭に浮かびます。 シフトまたはビットマスキングを実行するとき、値は別のものです。


2


int8_tとuint8_tの選択は、ptrをNULLと比較するときと同じです。

'' '' '

機能的には、NULLは0の#defineであるため、NULLと比較することは0と比較することと同じです。

しかし、個人的には、コーディングスタイルの観点から、ポインターをNULLと比較することにしました。NULL#defineは、不適切なポインターをチェックしているというコードを保守している人を意味します。

VS

誰かが0との比較を見たとき、それはあなたが特定の値をチェックしていることを意味します。

'' '' '

上記の理由から、私はuint8_tを使用します。


0


要素をより広い変数にフェッチすると、もちろんそれは符号拡張されるかどうかはわかりません。


0


すべきであるべきである…​ データのバイナリ性を強調したいのであれば、「生」で、「ちょっと、ちょっとした「整数」の束にすぎない」と言ってもらいたくないので、私は_署名をしない傾向があります。

バイトのバッファを表すために明示的な `signed char`を使ったことは一度もないと思います。

もちろん、3つ目の選択肢はバッファをできるだけ `void *`として表現することです。 多くの一般的なI / O関数は `void *`で動作します。そのため、使用する整数型の決定が完全にカプセル化されている場合があります。これは素晴らしいことです。