web-dev-qa-db-ja.com

文字に署名することはどういう意味ですか?

符号付き整数と符号なし整数は同じレジスタなどを使用し、ビットパターンの解釈が異なるだけで、C文字は基本的に8ビット整数であるとすると、Cの符号付き文字と符号なし文字の違いは何ですか? charの符号は実装で定義されていることを理解しています。少なくとも、charが数学ではなく文字列を保持するために使用されている場合、それがどのように違いを生むのか理解できません。

21
dsimcha

文字列には違いはありません。しかし、Cでは、charを使用して数学を行うことができます。

実際、組み込み8ビットアプリケーションのような制約のあるメモリ環境で作業する場合、charは数学を行うためによく使用され、それが大きな違いを生みます。これは、Cにはデフォルトでbyte型がないためです。

25
Nick Fortescue

それらが表す値に関して:

unsigned char:

  • 値の範囲にまたがる0..255 (00000000..11111111)
  • 値は次のようにローエッジの周りにオーバーフローします。

    0 - 1 = 255 (00000000 - 00000001 = 11111111)

  • 値は次のようにハイエッジの周りにオーバーフローします。

    255 + 1 = 0 (11111111 + 00000001 = 00000000)

  • ビット単位の右シフト演算子(_>>_)は、論理シフトを実行します。

    10000000 >> 1 = 01000000 (128 / 2 = 64)

符号付き文字:

  • 値の範囲にまたがる-128..127 (10000000..01111111)
  • 値は次のようにローエッジの周りにオーバーフローします。

    -128 - 1 = 127 (10000000 - 00000001 = 01111111)

  • 値は次のようにハイエッジの周りにオーバーフローします。

    127 + 1 = -128 (01111111 + 00000001 = 10000000)

  • ビット単位の右シフト演算子(_>>_)は、算術シフトを実行します。

    10000000 >> 1 = 11000000 (-128 / 2 = -64)

値の折り返し動作が純粋で一貫性のあるバイナリ演算であり、符号付き/符号なしの文字とは関係がないことを示すために、バイナリ表現を含めました(右シフトを想定)。

更新

コメントで言及されているいくつかの実装固有の動作:

22
Ates Goral
#include <stdio.h>

int main(int argc, char** argv)
{
    char a = 'A';
    char b = 0xFF;
    signed char sa = 'A';
    signed char sb = 0xFF;
    unsigned char ua = 'A';
    unsigned char ub = 0xFF;
    printf("a > b: %s\n", a > b ? "true" : "false");
    printf("sa > sb: %s\n", sa > sb ? "true" : "false");
    printf("ua > ub: %s\n", ua > ub ? "true" : "false");
    return 0;
}


[root]# ./a.out
a > b: true
sa > sb: true
ua > ub: false

文字列を並べ替えるときに重要です。

10
Quassnoi

いくつかの違いがあります。最も重要なことは、charの有効な範囲に大きすぎる整数または小さすぎる整数を割り当ててオーバーフローし、charが符号付きの場合、結果の値は実装で定義されるか、すべての符号付きタイプと同様に、何らかの信号(C)が発生する可能性があります。 。符号なし文字に大きすぎるまたは小さすぎるものを割り当てる場合とは対照的です。値が折り返されると、正確に定義されたセマンティクスが得られます。たとえば、unsigned charに-1を割り当てると、UCHAR_MAXが取得されます。したがって、0から2 ^ CHAR_BITまでの数値のようなバイトがある場合は常に、unsignedcharを使用して格納する必要があります。

符号は、vararg関数に渡すときにも違いがあります。

char c = getSomeCharacter(); // returns 0..255
printf("%d\n", c);

Cに割り当てられた値は、charが表すには大きすぎ、マシンは2の補数を使用するとします。多くの実装は、ビットパターンが変更されないという点で、charに大きすぎる値を割り当てた場合に動作します。 intがcharのすべての値を表すことができる場合(ほとんどの実装でそうです)、charはprintfに渡される前にintにプロモートされています。したがって、渡されるものの値は負になります。 intに昇格すると、その記号が保持されます。したがって、否定的な結果が得られます。ただし、charがunsignedの場合、値はunsignedであり、intに昇格すると、正のintが生成されます。 unsigned charを使用すると、変数への割り当てとprintfへの受け渡しの両方に対して正確に定義された動作が得られ、ポジティブなものが出力されます。

Char、unsigned、signed charはすべて少なくとも 8ビット幅であることに注意してください。 charが正確に 8ビット幅である必要はありません。ただし、ほとんどのシステムではそれが当てはまりますが、一部のシステムでは32ビット文字を使用していることがわかります。 CおよびC++のバイトはcharのサイズを持つように定義されているため、Cのバイトも必ずしも正確に8ビットであるとは限りません。

もう1つの違いは、Cでは、unsignedcharにパディングビットがあってはならないことです。つまり、CHAR_BITが8であることがわかった場合、unsignedcharの値は0 .. 2 ^ CHAR_BIT-1の範囲である必要があります。符号なしの場合、charについても同じことが言えます。符号付き文字の場合、コンパイラが符号を実装する方法(2の補数またはその他のオプション)を知っていても、値の範囲については何も想定できません。未使用のパディングビットが含まれている可能性があります。 C++では、3つの文字タイプすべてにパディングビットはありません。

「文字が署名されるとはどういう意味ですか?」

従来、ASCII文字セットは7ビットの文字エンコーディングで構成されています(8ビットのEBCIDICとは対照的です)。

C言語が設計および実装されたとき、これは重要な問題でした。 (シリアルモデムデバイスを介したデータ転送など、さまざまな理由で。)余分なビットにはパリティなどの用途があります。

「署名された文字」は、たまたまこの表現に最適です。

バイナリデータOTOHは、データの各8ビット「チャンク」の値を取得するだけなので、符号は必要ありません。

2
user50612

バイトの算術演算は、コンピュータグラフィックスにとって重要です(8ビット値は色を格納するためによく使用されます)。それとは別に、char記号が重要な2つの主なケースを考えることができます。

  • より大きなintに変換する
  • 比較関数

厄介なのは、すべての文字列データが7ビットの場合、これらはあなたを噛まないということです。ただし、C/C++プログラムを8ビットクリーンにしようとしている場合は、あいまいなバグの終わりのない原因になることが約束されています。

1
comingstorm

符号付きは、他の整数型とほぼ同じようにcharsで機能します。お気づきのように、charsは実際には1バイトの整数です。 (必ずしも8ビットではありませんただし、違いがあります。プラットフォームによっては、バイトが8ビットより大きくなる場合があります。また、charsizeof(char)CHAR_BITまたはC++の<limits.h>で定義されている<climits>マクロは、charに含まれるビット数を示します。).

記号付きの文字が必要な理由については、CおよびC++には、byteと呼ばれる標準の型はありません。コンパイラにとって、charsはバイトであり、その逆も同様であり、それらを区別しません。ただし、場合によっては、-場合によってはwantそのcharを1バイトの数値にしたい場合があります。そのような場合(特に、1バイトの範囲がどれだけ小さいか)、通常は番号が署名されているかどうか。私は個人的にsignedness(またはunsignedness)を使用して、特定のcharは文字ではなく(数値の)「バイト」であり、数値的に使用されると言っています。符号が指定されていない場合、そのcharは実際には文字であり、テキストとして使用することを目的としています。

むしろ、私はそれをしていました。現在、CおよびC++の新しいバージョンには(u?)int_least8_t(現在は<stdint.h>または<cstdint>でtypedefされています)があります。これはより明示的に数値です(ただし、通常はsignedおよびC++のtypedefになります。とにかく符号なしcharタイプ)。

1
cHao

これが問題であると私が想像できる唯一の状況は、文字で数学を行うことを選択した場合です。次のコードを書くことは完全に合法です。

char a = (char)42;
char b = (char)120;
char c = a + b;

文字の符号に応じて、cは2つの値のいずれかになります。 charが符号なしの場合、cは(char)162になります。それらが署名されている場合、署名された文字の最大値は128であるため、オーバーフローケースになります。ほとんどの実装は(char)-32を返すだけだと思います。

0
JaredPar

符号付き文字についての1つのことは、c> = ''(スペース)をテストして、それが通常の印刷可能なASCII文字であることを確認できることです。もちろん、ポータブルではないので、あまり役に立ちません。

0
user3458