warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
警告:符号の異なる整数式の比較
■この記事の概要
この記事では、C言語の0xFFFFFFFFが
符号付き整数では-1に、
符号なし整数では4294967295として扱われる理由を解説しています。
暗黙の型変換や符号拡張の挙動を詳述し、
バグ防止のために型変換を理解する重要性を
具体例を用いて解説しています。
■この記事の環境
ここでの解説はLP64-gcc/clangの環境を前提とします
(いわゆるlinux系64bitコンパイラ環境)。
8,16,32,128bitやLLP64
(いわゆるWindows系 64bitコンパイラ環境)は
考慮していません。
■奇妙なif文の実行結果を予想して下さい
●Q1:0xFFFFffffはマイナス壱と等しいのに正の巨大な数とも等しい?
#include <stdio.h>
//0xFFFFffffはマイナス壱と等しいのに
//正の巨大な数とも等しい?
int main(void){
if((0xFFFFffff==-1)&&(0xFFFFffff==4294967295))
puts("YES");
else
puts("NO");
}
●Q2:0xFFFFffffはマイナス壱と等しいのに零以上か?
#include <stdio.h>
//0xFFFFffffはマイナス壱と等しいのに零以上か?
int main(void){
if((0xFFFFffff==-1)&&(0xFFFFffff>=0))
puts("YES");
else
puts("NO");
}
●Q3:16進数と10進数の足し算の結果は同じか?
#include <stdio.h>
//16進数と10進数の足し算の結果は同じか?
int main(void){
if((0xFFFFffff+1)==(4294967295+1))
puts("YES");
else
puts("NO");
}
●Q4:if((x==y)&&(y==z)&&(x!=z))は成り立つか?
#include <stdio.h>
//if((x==y)&&(y==z)&&(x!=z))は成り立つか?
int main(void){
int x = -1;
unsigned int y = 0xFFFFffff ;
long z = 4294967295 ;
if((x == y) && (y == z) && (x != z))
puts("YES");
else
puts("NO");
}
■定数の型を文字列で表示する方法とは?
#include <stdio.h>
#define typename(x) _Generic((x),\
char: "char",\
short: "short",\
int: "int",\
unsigned int:"unsigned int",\
long: "long",\
default: "other"\
)
int main(void){
printf("%s %zu\n",typename(-1),sizeof(-1));
printf("%s %zu\n",typename(0),sizeof(0));
printf("%s %zu\n",typename(1),sizeof(1));
printf("%s %zu\n",typename(0xFFFFffff),sizeof(0xFFFFffff));
printf("%s %zu\n",typename(4294967295),sizeof(4294967295));
}
注意:
_GenericはC11で採用された新しい機能なので古いコンパイラでは動きません。
●実行結果
./a.out
int 4
int 4
int 4
unsigned int 4
long 8
●-1とは?
・int型4byteの負の定数です
●0xffffffffとは?
・unsigned int型4byteの正の定数です
●4294967295とは?
・long型8byteの正の定数です
■0xffffffffと-1のビットパターンは同じ
#include <stdio.h>
#include <string.h>
#include <stdint.h>
int main(void){
int32_t s = -1 ;
uint32_t u = 0xffffffff ;
if(memcmp(&s,&u,sizeof(s)) == 0){
printf("%d と %x のビットパターンは同じ\n",s,u);
}else{
puts("ここには来ない");
}
}
➡LP64での実行結果
./a.out
-1 と ffffffff のビットパターンは同じ
■-1と0xffffffffと4294967295と暗黙の型変換
・if(0xffffffff == -1)のような
符号無し(0xffffffff)と符号付き(-1)の比較は
符号付き-1のほうが符号無しに拡張され
双方同じ符号無しになってから比較されます。
簡単に言うと演算子の両辺の型が違う場合
狭い型は
広い型に格上げされてから演算されます。
このため0xffffffffと -1は等しくなります。
先のQ4で発生している暗黙の型変換を
明示すると次の型変換が発生しています。
#include <stdio.h>
//if((x==y)&&(y==z)&&(x!=z))は成り立つか?
int main(void){
int x = -1;
unsigned int y = 0xFFFFffff ;
long z = 4294967295 ;
if(((unsigned int)x == y) && ((long)y == z) && ((long)x != z))
puts("YES");
else
puts("NO");
}
参考: