文字が署名されるとはどういう意味ですか?
-
19-08-2019 - |
質問
符号付き整数と符号なし整数は同じレジスタなどを使用し、ビットパターンを異なる方法で解釈するだけであり、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)
)は算術シフトを実行します:<=>
値のラッピング動作が純粋で一貫性のあるバイナリ算術であり、符号付き/符号なしの文字とは無関係であることを示すために、バイナリ表現を含めました(右シフトが必要です)。
更新
コメントに記載されている実装固有の動作:
- char!=署名されたchar。タイプ<!> quot; char <!> quot; <!> quot; signed <!> quot;なしまたは<!> quot; unsinged <!> quot;実装定義であるため、符号付きまたは符号なしの型のように動作できます。
- 符号付き整数オーバーフローは、コアのダンプやバッファのオーバーランなど、プログラムが何でもできる未定義の動作につながります。
#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文字であることを確認できることです。もちろん、ポータブルではないため、あまり便利ではありません。