質問

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

役に立ちましたか?

解決

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

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

他のヒント

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

unsigned char:

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

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

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

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

  • ビット単位の右シフト演算子(>>)は論理シフトを行います:

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

signed char:

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

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

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

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

  • ビット単位の右シフト演算子(10000000 >> 1 = 11000000 (-128 / 2 = -64))は算術シフトを実行します:

    <=>

値のラッピング動作が純粋で一貫性のあるバイナリ算術であり、符号付き/符号なしの文字とは無関係であることを示すために、バイナリ表現を含めました(右シフトが必要です)。

更新

コメントに記載されている実装固有の動作:

#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

文字列をソートするときは重要です。

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

また、vararg関数に渡すときに符号が異なります:

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

cに割り当てられた値がcharで表現するには大きすぎると仮定し、マシンは2の補数を使用します。多くの実装は、ビットパターンが変更されないという点で、charに大きすぎる値を割り当てた場合に動作します。 intがcharのすべての値を表すことができる場合(ほとんどの実装の場合)、charはprintfに渡される前にintに昇格されます。したがって、渡される値は負になります。 intに昇格すると、その記号が保持されます。したがって、否定的な結果が得られます。ただし、charが符号なしの場合、値は符号なしであり、intに昇格すると正のintが生成されます。 unsigned charを使用すると、変数への代入とprintfに渡すことにより、明確に定義された動作を正確に定義した動作が得られます。

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

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

  
    

<!> quot; charが署名されるとはどういう意味ですか?<!> quot;

  

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

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

A <!> quot;符号付き文字<!> quot;この表現に最適です。

バイナリデータOTOHは、各8ビット<!> quot; chunk <!> quotの値を単純に取得しています。データのため、記号は不要です。

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

  • より大きな整数への変換
  • 比較関数

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

Signednessは、他の整数型と同じようにchar sで機能します。既に説明したように、charsは実際には1バイトの整数です。 (ただし、必ずしも8ビットである必要はありません!違いがあります。一部のプラットフォームでは1バイトが8ビットより大きい場合があり、sizeof(char)の定義により、CHAR_BITはむしろバイトに関連付けられますおよび<limits.h><climits>またはC ++のbyteで定義されている(u?)int_least8_tマクロは、<stdint.h>に含まれるビット数を示します。)

符号付きの文字が必要な理由については、CおよびC ++には、<cstdint>という標準タイプはありません。コンパイラにとって、<=>はバイトであり、その逆もまた同じであり、それらを区別しません。ただし、場合によっては、その<=>が1バイトの数字になるように したいこともあります。そのような場合(特に、バイトが持つことができる範囲がどれだけ小さいか)、番号が署名されているかどうかに注意してください。特定の<=>が(数値)<!> quot; byte <!> quot;であると言うために、私は個人的に符号付き(または符号なし)を使用しました。キャラクターではなく、数値的に使用されること。指定された署名なしでは、その<=>は実際には文字であり、テキストとして使用されることを意図しています。

以前はそうしていました。 CおよびC ++の新しいバージョンには<=>(現在は<=>または<=>でtypedefされています)があり、これはより明示的に数値です(ただし、通常は符号付きおよび符号なし<=>型のtypedefになります) )。

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

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

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

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

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