12

私は、C++ でバイトを扱うときに char を使用するライブラリを頻繁に使用します。別の方法は、「Byte」を unsigned char として定義することですが、使用することを決定した標準ではありません。私は頻繁に C# から C++ dll にバイトを渡し、それらを char にキャストしてライブラリを操作します。

int を chars に、または chars を他の単純な型にキャストする場合、発生する可能性のある副作用にはどのようなものがありますか。具体的には、あなたが取り組んできたこの壊れたコードはいつ発生し、どのようにして char の符号が原因であることがわかりましたか?

幸いなことに、コードでこれに遭遇したことはありません。学校の組み込みシステムのクラスで、char 署名されたキャスト トリックを使用しました。私が行っている仕事に関連していると感じているので、この問題をよりよく理解したいと思っています。

4

8 に答える 8

4

1 つの主要なリスクは、バイトをシフトする必要がある場合です。signed char は右シフトされたときに符号ビットを保持しますが、unsigned char は保持しません。ここに小さなテストプログラムがあります:

#include <stdio.h>

int main (void)
{
    signed char a = -1;
    unsigned char b = 255;

    printf("%d\n%d\n", a >> 1, b >> 1);

    return 0;
}

a と b が同じビット パターンで始まる場合でも、-1 と 127 を出力する必要があります (8 ビット文字、2 の補数、および算術シフトを使用した符号付きの値が与えられた場合)。

つまり、符号付きと符号なしの char に対して shift が同じように機能することに依存することはできないため、移植性が必要な場合は、 orunsigned charではなくを使用してください。charsigned char

于 2010-02-03T15:21:31.190 に答える
2

char最も明白な落とし穴は、プロトコルまたはエンコーディングスキームを実装するときに、aの数値を16進定数と比較する必要がある場合に発生します。

たとえば、telnetを実装する場合、これを実行することができます。

// Check for IAC (hex FF) byte
if (ch == 0xFF)
{
    // ...

または、UTF-8マルチバイトシーケンスをテストする場合。

if (ch >= 0x80)
{
    // ...

char幸いなことに、これらのエラーは、署名されたプラットフォームでの最も大雑把なテストでさえも明らかになるはずなので、通常はそれほど長くは存続しません。これらは、文字定数を使用するか、数値定数をaに変換するか、比較演算子が両方をにプロモートする前にchar文字をaに変換することで修正できます。ただし、直接をに変換することはできません。unsigned charintcharunsigned

if (ch == '\xff')               // OK

if ((unsigned char)ch == 0xff)  // OK, so long as char has 8-bits

if (ch == (char)0xff)           // Usually OK, relies on implementation defined behaviour

if ((unsigned)ch == 0xff)       // still wrong
于 2010-02-03T20:20:27.537 に答える
1

私を最も悩ませているもの:

typedef char byte;

byte b = 12;

cout << b << endl;

確かに化粧品だけど…

于 2010-02-03T15:12:27.653 に答える
1

私は、テキストの文字を状態ツリーへのインデックスとして使用する検索アルゴリズムを作成する際に、char 符号に悩まされてきました。また、文字をより大きな型に展開するときに問題が発生し、符号ビットが伝播して他の場所で問題が発生しました。

奇妙な結果が得られ始めたとき、および初期開発中に使用したもの以外のテキストを検索することから生じるセグメンテーション違反を発見しました (明らかに、値が 127 より大きいまたは 0 より小さい文字がこれを引き起こす可能性があり、必ずしもそうであるとは限りません)。通常のテキスト ファイルに存在します。

変数を操作するときは、常に変数の符号を確認してください。一般的に、特に理由がない限り、必要に応じてキャストして、型に署名を付けます。charこれは、単純にバイトを表す in ライブラリのユビキタスな使用法にうまく適合します。の符号性charは (他の型とは異なり) 定義されていないことに注意してください。特別な扱いをする必要があり、注意が必要です。

于 2010-02-03T15:16:38.863 に答える
0

サイン延長。URL エンコーディング関数の最初のバージョンでは、"%FFFFFFA3" のような文字列が生成されました。

于 2010-06-12T07:10:48.783 に答える
0

C++ 標準は特定の「符号付き」であることを定義していないため、複数のプラットフォーム用にコンパイルすると惨めに失敗しますchar

したがって、GCC は、特定の動作を強制するオプションを導入-fsigned-charしています。-funsigned-charこのトピックの詳細については、たとえば、こちらを参照してください。

編集:

壊れたコードの例を尋ねられたように、バイナリ データを処理するコードが壊れる可能性はたくさんあります。たとえば、8 ビットのオーディオ サンプル (範囲 -128 ~ 127) を処理し、音量を半分にしたい画像。ここで、次のシナリオを想像してください (素朴なプログラマーは を想定していますchar == signed char)。

char sampleIn;

// If the sample is -1 (= almost silent), and the compiler treats char as unsigned,
// then the value of 'sampleIn' will be 255
read_one_byte_sample(&sampleIn);

// Ok, halven the volume. The value will be 127!
char sampleOut = sampleOut / 2;

// And write the processed sample to the output file, for example.
// (unsigned char)127 has the exact same bit pattern as (signed char)127,
// so this will write a sample with the loudest volume!!
write_one_byte_sample_to_output_file(&sampleOut);

この例を気に入っていただければ幸いです ;-) しかし、正直なところ、覚えている限り、初心者でさえ、そのような問題に実際に遭遇したことはありません...

この回答があなたの反対投票者にとって十分であることを願っています。短いコメントはどうですか?

于 2010-02-03T15:37:38.923 に答える
0

int を chars に、または chars を他の単純な型にキャストする場合

重要な点は、符号付きの値をあるプリミティブ型から別の (より大きな) 型にキャストすると、ビット パターンが保持されないことです (2 の補数を想定)。ビット パターンを持つ signed char0xffは -1 ですが、10 進値 -1 を持つ signed short は です0xffff。ただし、値を持つ unsigned char を0xffunsigned short にキャストすると、 が生成され0x00ffます。したがって、より大きなデータ型またはより小さなデータ型に型キャストする前に、常に適切な符号について考えてください。必要がない場合は、符号付きデータ型で符号なしデータを保持しないでください。外部ライブラリによって強制される場合は、できるだけ遅く (または外部コードがデータ ソースとして機能する場合はできるだけ早く) 変換を行ってください。

于 2010-02-03T15:24:15.643 に答える
0

C および C++ 言語仕様では、文字を保持するため charに 、signed charおよびの 3 つのデータ型が定義されていunsigned charます。後者の2つは他の回答で議論されています。charタイプを見てみましょう。

標準では、charデータ型符号付きまたは符号なしである可能性があり、実装上の決定であると述べています。これは、一部のコンパイラまたはコンパイラのバージョンがchar異なる方法で実装できることを意味します。charこれは、データ型が算術演算またはブール演算に適していないことを意味します。算術演算とブール演算についてはsigned、 のunsignedバージョンでchar問題なく動作します。

要約すると、charデータ型には 3 つのバージョンがあります。このデータ型は、文字の保持には適していますが、符号の有無は実装で定義されるcharため、プラットフォームやトランスレーターにまたがる算術演算には適していません。

于 2010-02-03T17:54:04.007 に答える