Last Update 2021/09/14
-Wshift-count-overflow
シフト演算の祭に、「シフトカウント>=タイプ幅」に該当する場合は警告を出力
テスト概要
オプション無し、-Wshift-count-overflowオプションを使用した際の警告出力例
実行環境
GCC-8.2.0
GNU C Library 2.28
GNU Binutils 2.31.1
GNU C Library 2.28
GNU Binutils 2.31.1
コード例・出力内容中の表記
・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。
使用ファイル
sample.c
#include <stdio.h>
#include <limits.h>
int main(void)
{
unsigned char uc1 = UCHAR_MAX; /* 8bit */
unsigned char uc2 = UCHAR_MAX; /* 8bit */
unsigned char uc3 = UCHAR_MAX; /* 8bit */
unsigned int ui1 = UINT_MAX; /* 32bit */
unsigned int ui2 = UINT_MAX; /* 32bit */
unsigned int ui3 = UINT_MAX; /* 32bit */
unsigned long ul1 = ULONG_MAX; /* 64bit */
unsigned long ul2 = ULONG_MAX; /* 64bit */
unsigned long ul3 = ULONG_MAX; /* 64bit */
printf("***** 演算前 *****\n");
printf("uc1 = %016lx(%lu)\n", uc1, uc1);
printf("ui1 = %016lx(%lu)\n", ui1, ui1);
printf("ul1 = %016lx(%lu)\n", ul1, ul1);
printf("uc2 = %016lx(%lu)\n", uc2, uc2);
printf("ui2 = %016lx(%lu)\n", ui2, ui2);
printf("ul2 = %016lx(%lu)\n", ul2, ul2);
printf("uc3 = %016lx(%lu)\n", uc3, uc3);
printf("ui3 = %016lx(%lu)\n", ui3, ui3);
printf("ul3 = %016lx(%lu)\n", ul3, ul3);
/* シフトカウント = 最大幅 - 1 */
uc1 = uc1 >> 8 - 1;
ui1 = ui1 >> 32 - 1;
ul1 = ul1 >> 64 - 1;
/* シフトカウント = 最大幅 */
uc2 = uc2 >> 8;
ui2 = ui2 >> 32;
ul2 = ul2 >> 64;
/* 2回に分割して演算 */
/* [1] シフトカウント = 最大幅 - 1 */
/* [2] シフトカウント = 1 */
uc3 = uc3 >> 8 - 1;
ui3 = ui3 >> 32 - 1;
ul3 = ul3 >> 64 - 1;
uc3 = uc3 >> 1;
ui3 = ui3 >> 1;
ul3 = ul3 >> 1;
printf("***** 演算後 *****\n");
printf("uc1 = %016lx(%lu)\n", uc1, uc1);
printf("ui1 = %016lx(%lu)\n", ui1, ui1);
printf("ul1 = %016lx(%lu)\n", ul1, ul1);
printf("uc2 = %016lx(%lu)\n", uc2, uc2);
printf("ui2 = %016lx(%lu)\n", ui2, ui2);
printf("ul2 = %016lx(%lu)\n", ul2, ul2);
printf("uc3 = %016lx(%lu)\n", uc3, uc3);
printf("ui3 = %016lx(%lu)\n", ui3, ui3);
printf("ul3 = %016lx(%lu)\n", ul3, ul3);
return 0;
}
動作テスト
オプション無しでコンパイルを実行
$ gcc sample.c
sample.c: In function ‘main’:
sample.c:34:12: warning: right shift count >= width of type [-Wshift-count-overflow]
ui2 = ui2 >> 32;
^~
sample.c:35:12: warning: right shift count >= width of type [-Wshift-count-overflow]
ul2 = ul2 >> 64;
^~
$ ./a.out
***** 演算前 *****
uc1 = 00000000000000ff(255)
ui1 = 00000000ffffffff(4294967295)
ul1 = ffffffffffffffff(18446744073709551615)
uc2 = 00000000000000ff(255)
ui2 = 00000000ffffffff(4294967295)
ul2 = ffffffffffffffff(18446744073709551615)
uc3 = 00000000000000ff(255)
ui3 = 00000000ffffffff(4294967295)
ul3 = ffffffffffffffff(18446744073709551615)
***** 演算後 *****
uc1 = 0000000000000001(1)
ui1 = 0000000000000001(1)
ul1 = 0000000000000001(1)
uc2 = 0000000000000000(0)
ui2 = 00000000ffffffff(4294967295)
ul2 = ffffffffffffffff(18446744073709551615)
uc3 = 0000000000000000(0)
ui3 = 0000000000000000(0)
ul3 = 0000000000000000(0)
$ unsigned charに関しては整数拡張されていると思われ、uc2の演算では警告は発生しない
警告が発生した2つの変数に関しては該当する演算結果にシフト操作は反映されていない
-Wshift-count-overflowオプション使用してコンパイルを実行
$ gcc -Wshift-count-overflow sample.c
sample.c: In function ‘main’:
sample.c:34:12: warning: right shift count >= width of type [-Wshift-count-overflow]
ui2 = ui2 >> 32;
^~
sample.c:35:12: warning: right shift count >= width of type [-Wshift-count-overflow]
ul2 = ul2 >> 64;
^~
$ -Wshift-count-overflowオプションはデフォルトで有効であるためオプション無しと同じ結果となる