BLOGTIMES
2021/12/19

scanf() で整数を 1 バイト分だけ読み取る

  c 
このエントリーをはてなブックマークに追加

最近の gcc はチェックが厳しくなっているので scanf() を使って int の値を char に書込むと *** stack smashing detected *** というエラーが出るようです。

例えば 10 進の値を char に代入するようなプログラムは C 言語の入門などでよく出てきます。

test.c

#include <stdio.h> int main(void){ char c; printf("文字コード: "); scanf("%d", &c); printf("文字コード%dの文字は'%c'です\n",c,c); return 0; }

コンパイルすると警告が出る

これを単純にコンパイルすると、以下のように警告が出ます
これを見て驚くのは、最近の gcc はエラーや警告メッセージがかなり丁寧になっているということ。

これをきちんと読めば、scanf() に含まれる書式指定 %d は可変長引数部分の int * に対応していなければならないのに対して、実際の可変長引数部分の型は char * になっているので、型があっていないというのがきちんと分かります。

これを修正するための候補として %hhd も挙げられていますね。

$ gcc --version gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gcc test.c test.c: In function ‘main’: test.c:6:10: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘char *’ [-Wformat=] 6 | scanf("%d", &c); | ~^ ~~ | | | | | char * | int * | %hhd

とりあえず無理やり実行してみる

とりあえずコンパイル自身はされているので、警告を無視して実行してみます。
結果は表示されますが、実行時エラーが出て正常終了しません

$ ./a.out 文字コード: 100 文字コード100の文字は'd'です *** stack smashing detected ***: terminated Aborted

実行時のエラーの原因は char (1B) の領域に無理やり int (4B) 分のデータを書込んでしまうからですね。
要はバッファーオーバーフローです。

このバッファオーバーフローが gcc の stack protector*1 によって検知されていることになります。
実行結果が表示されてしまっているのは、stack protector が関数の実行後(今回の場合は main()の実行終了時 )にバッファオーバーフローを検出しているためです。

書式を修正してみる

gcc の警告のアドバイスに従って書式を %hhdにしてみるとコンパイルの警告、実行時エラー共に解消しました。

サイズ的には %d→4B、%hd→2B、%hhd→1B となるようなので、h は half の h でしょうか(llongl だと分かるのですが)。

test.c

#include <stdio.h> int main(void){ char c; printf("文字コード: "); scanf("%hhd", &c); printf("文字コード%dの文字は'%c'です\n",c,c); return 0; }
$ gcc test.c $ ./a.out 文字コード: 100 文字コード100の文字は'd'です

ちなみに調べてみたら h 接頭辞は C99 から使えるようになっていたようです。


トラックバックについて
Trackback URL:
お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/12934
Trackbacks
このエントリにトラックバックはありません
Comments
愛のあるツッコミをお気軽にどうぞ。[policy]
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントはありません
Comments Form

コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。

OpenID を使ってログインすることができます。

Identity URL: Yahoo! JAPAN IDでログイン