署名された/署名されていない比較に関するこの質問を読んだ後(彼らは私が言うだろう数日ごとに出てきます):
なぜ適切な署名された署名されていない比較がなく、代わりにこの恐ろしい混乱があるのだろうか?この小さなプログラムから出力を取得します。
#include <stdio.h>
#define C(T1,T2)\
{signed T1 a=-1;\
unsigned T2 b=1;\
printf("(signed %5s)%d < (unsigned %5s)%d = %d\n",#T1,(int)a,#T2,(int)b,(a<b));}\
#define C1(T) printf("%s:%d\n",#T,(int)sizeof(T)); C(T,char);C(T,short);C(T,int);C(T,long);
int main()
{
C1(char); C1(short); C1(int); C1(long);
}
私の標準コンパイラ(gcc、64ビット)でコンパイルすると、次のようになります。
char:1
(signed char)-1 < (unsigned char)1 = 1
(signed char)-1 < (unsigned short)1 = 1
(signed char)-1 < (unsigned int)1 = 0
(signed char)-1 < (unsigned long)1 = 0
short:2
(signed short)-1 < (unsigned char)1 = 1
(signed short)-1 < (unsigned short)1 = 1
(signed short)-1 < (unsigned int)1 = 0
(signed short)-1 < (unsigned long)1 = 0
int:4
(signed int)-1 < (unsigned char)1 = 1
(signed int)-1 < (unsigned short)1 = 1
(signed int)-1 < (unsigned int)1 = 0
(signed int)-1 < (unsigned long)1 = 0
long:8
(signed long)-1 < (unsigned char)1 = 1
(signed long)-1 < (unsigned short)1 = 1
(signed long)-1 < (unsigned int)1 = 1
(signed long)-1 < (unsigned long)1 = 0
32ビット用にコンパイルした場合、結果は次の点を除いて同じです。
long:4
(signed long)-1 < (unsigned int)1 = 0
「どうやって?」これらすべての中で簡単に見つけることができます。C99標準のセクション6.3またはC++の第4章に移動し、オペランドが共通型に変換される方法を説明する句を掘り下げてください。共通型が負の値を再解釈すると、これが機能しなくなる可能性があります。
しかし、「なぜ?」はどうですか。ご覧のとおり、「<」はすべてのケースの50%で失敗します。また、タイプの具体的なサイズに依存するため、プラットフォームに依存します。考慮すべき点は次のとおりです。
変換と比較のプロセスは、驚き最小の原則の代表的な例ではありません。
私は、テロリストによって書かれて
(short)-1 > (unsigned)1
いないという命題に依存しているコードがそこにあるとは思わない。テンプレートコードを使用してC++を使用している場合、これはすべてひどいものです。正しい「<」を編成するには、型特性の魔法が必要だからです。
結局のところ、さまざまなタイプの符号付き値と符号なし値を比較するのは簡単です。
signed X < unsigned Y -> (a<(X)0) || ((Z)a<(Z)b) where Z=X|Y
事前チェックは安価であり、a> = 0が静的に証明できる場合は、コンパイラーによって最適化することもできます。
だからここに私の質問があります:
C / C ++と比較して安全な符号付き/符号なしの比較を追加すると、言語または既存のコードが壊れますか?
(「言語が壊れますか」とは、この変更に対応するために、言語のさまざまな部分に大規模な変更を加える必要があることを意味します)
更新: これを古き良きTurbo-C ++ 3.0で実行し、次の出力を取得しました:
char:1
(signed char)-1 < (unsigned char)1 = 0
なぜ(signed char)-1 < (unsigned char) == 0
ここにあるのですか?