たとえば、から(または単に?)に変換するのは安全unsigned char *
ですsigned char *
かchar *
?
8 に答える
アクセスは明確に定義されており、オブジェクトの動的型に対応する符号付きまたは符号なしの型へのポインタを介してオブジェクトにアクセスできます (3.10/15)。
さらに、signed char
トラップ値がないことが保証されているため、元のオブジェクトsigned char
の値に関係なく、ポインターを安全に読み取ることができます。unsigned char
もちろん、一方のポインターから読み取った値が、もう一方のポインターから読み取った値と異なることは予想できます。
編集:セリビッツェのコメントに関して、これは 3.9.1/1 が言っていることです。
char、signed char、および unsigned char は、同じ量のストレージを占有し、同じ整列要件 (3.9) を持ちます。つまり、それらは同じオブジェクト表現を持っています。文字型の場合、オブジェクト表現のすべてのビットが値表現に関与します。符号なし文字タイプの場合、値表現の可能なすべてのビット パターンは数値を表します。
したがって、実際にsigned char
はトラップ値があるようです。ナイスキャッチ!
キャストはタイプを変更しますが、ビット表現には影響しません。unsignedcharからsignedcharにキャストしても、値はまったく変更されませんが、値の意味に影響します。
次に例を示します。
#include <stdio.h>
int main(int args, char** argv) {
/* example 1 */
unsigned char a_unsigned_char = 192;
signed char b_signed_char = b_unsigned_char;
printf("%d, %d\n", a_signed_char, a_unsigned_char); //192, -64
/* example 2 */
unsigned char b_unsigned_char = 32;
signed char a_signed_char = a_unsigned_char;
printf("%d, %d\n", b_signed_char, b_unsigned_char); //32, 32
return 0;
}
最初の例では、値が192、またはバイナリで110000000のunsignedcharがあります。signed charにキャストした後も、値は110000000のままですが、これはたまたま-64の2s補数表現です。符号付きの値は、2秒補数表現で保存されます。
2番目の例では、符号なしの初期値(32)が128未満であるため、キャストの影響を受けていないように見えます。バイナリ表現は00100000であり、2秒補数表現では32のままです。
unsignedcharからsignedcharに「安全に」キャストするには、値が128未満であることを確認してください。
あるタイプの文字から同じサイズの別のタイプの文字に変換するだけなので、変換は安全である必要があります。2つのデータ型の数値範囲は異なるため、ポインターを逆参照するときにコードが期待するデータの種類に注意してください。(つまり、ポインターが指す数値が元々符号なしとして正であった場合、ポインターが符号付き文字*に変換され、それを逆参照すると、負の数値になる可能性があります。)
ポインタをどのように使用するかによって異なります。ポインタ型を変換しているだけです。
呼び出している関数は char ポインターからの動作を期待するため、 anunsigned char*
を aに安全に変換できますが、char 値が 127 を超えると、期待したものとは異なる結果が得られるため、確認してください。char *
符号なし配列にあるものが符号付き配列に対して有効であること。
unsigned char から signed char に変換するなど、いくつかの点でうまくいかないことがわかりました。
1 つは、配列のインデックスとして使用している場合、そのインデックスが負になる可能性があることです。
第 2 に、switch ステートメントに入力すると、多くの場合、switch が想定していない負の入力が発生する可能性があります。
第三に、算術右シフトでは異なる動作をします
int x = ...;
char c = 128
unsigned char u = 128
c >> x;
とは異なる結果になる
u >> x;
前者は符号拡張され、後者はそうではないためです。
第 4 に、符号付き文字は、符号なし文字とは異なるポイントでアンダーフローを引き起こします。
したがって、一般的なオーバーフロー チェックは、
(c + x > c)
とは異なる結果を返す可能性があります
(u + x > u)
ASCII データのみを扱う場合は安全です。
まだ言及されていないことに驚いています.Boost数値キャストはうまくいくはずですが、もちろんデータに対してのみです.
ポインターは常にポインターです。それらを別の型にキャストすることで、コンパイラが指すデータを解釈する方法を変更するだけです。