chars の署名による最悪の副作用。(charsとcastsに対するsignednessの影響の説明)

StackOverflow https://stackoverflow.com/questions/2192880

質問

私は C++ でバイトを扱うときに、char を使用するライブラリを頻繁に扱います。代替案は、「バイト」を unsigned char として定義することですが、これは使用することを決定した標準ではありません。私は頻繁に C# から C++ DLL にバイトを渡し、それを char にキャストしてライブラリで動作させます。

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

幸運なことに、私は自分のコードでこれに遭遇したことがなく、学校の組み込みシステムの授業で char 署名付きのキャスト トリックを使用しました。この問題は私が行っている仕事に関連していると思うので、より深く理解したいと考えています。

役に立ちましたか?

解決

大きなリスクの1つは、バイトをシフトする必要がある場合です。署名された文字は、右シフトしたときにサインビットを保持しますが、署名されていないチャーはそうではありません。これが小さなテストプログラムです:

#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は同じビットパターン(8ビットCHAR、2つの補完、算術シフトを使用して署名された値が与えられます)で始まりますが、-1と127を印刷する必要があります。

要するに、あなたは署名されたチャーと署名されていない文字のために同じようにシフトの作業に頼ることができないので、あなたが移植性が必要な場合は、使用してください unsigned char それよりも char また signed char.

他のヒント

あなたがの数値を比較する必要があるときに最も明白なゴッチャは来ます char プロトコルまたはエンコードスキームを実装するときに16進定数があります。

たとえば、Telnetを実装するときは、これを行うことをお勧めします。

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

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

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

幸いなことに、これらのエラーは通常、署名済みのプラットフォームで最も大まかなテストでさえあまり生き残れません char それらを明らかにする必要があります。それらは、数値定数をに変換する文字定数を使用して固定できます char または、文字をanに変換します unsigned char 比較演算子が両方に宣伝する前に int. 。変換 char 直接 unsigned ただし、機能しません。

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

私は、テキストの文字をインデックスとして状態ツリーに使用した検索アルゴリズムを書く際のチャーサインを噛みました。また、文字をより大きなタイプに拡大するときに問題を引き起こしましたが、サインビットは他の場所で問題を引き起こします。

奇妙な結果が得られ始めたとき、最初の開発中に使用したテキスト以外のテキストを検索することから生じるセグフォルト(明らかに値を> 127または<0のキャラクターがこれを引き起こすとは限りません。典型的なテキストファイルに存在します。

変数を使用するときは、常に変数の署名を確認してください。一般的に、私は特に正当な理由がない限り、タイプを署名します。必要に応じてキャストします。これは、ユビキタスな使用にうまく適合します char ライブラリでは、単純にバイトを表します。の署名に留意してください char 定義されていません(他のタイプとは異なります)、特別な治療を行い、注意してください。

最もイライラするもの:

typedef char byte;

byte b = 12;

cout << b << endl;

確かにそれは化粧品ですが、arrr ...

intを他の単純なタイプにcharまたはcharsに鋳造するとき

重要なポイントは、1つのプリミティブタイプから別のタイプ(より大きな)タイプに署名された値をキャストしても、ビットパターンを保持しないことです(2つの補数を仮定)。ビットパターンを備えた署名型チャー 0xff IS -1、一方、小数値-1で署名された短い署名 0xffff. 。価値のある署名のない文字をキャストします 0xff ただし、署名されていないショートになります 0x00ff. 。したがって、より大きなデータ型または小さいデータ型にタイプキャストする前に、常に適切な署名を考えてください。 必要でない場合は、署名されたデータ型に署名されていないデータを携帯しないでください - 外部ライブラリがそうすることを強制する場合は、できるだけ遅く(または外部コードがデータソースとして機能する場合はできるだけ早く)変換を行います。

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

標準はそれを言います char データ・タイプ 五月 署名されます また 署名されておらず、実装決定です。これは、コンパイラの一部のコンパイラまたはバージョンが実装できることを意味します char 違う。意味は、 char データ型は、算術操作またはブール操作を助長しません。算術およびブール操作の場合、 signedunsigned のバージョン char 正常に動作します。

要約すると、3つのバージョンがあります char データ・タイプ。 char データ型は文字を保持するのに適していますが、プラットフォームと翻訳者間の算術には適していません。 署名 実装は定義されています。

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);

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

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

サインエクステンション。私のURLエンコード関数の最初のバージョンは、「%FFFFFFA3」のような文字列を生成しました。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top