金曜はアセンブリ言語の授業。
アセンブラは凄く苦手でそれほど好きじゃないんですが、やっぱり覚えておいた方がいいと思うので授業を受けることに。
少しだけわくわくしながら出席。
ところが今日はアセンブラというより単なる2の補数の話。
ガッカリだよ!と思いきや(授業後の質問も含めて)意外と勉強になったこともあったのでメモしておくことにする。
1.stdint.h
C言語のint型のサイズはプラットフォーム依存。
そこでその差を吸収するためにstdint.hがあり、プログラム中でint32_t value;とすることで符号あり32bit整数を安全に使うことができる。
Q.
で、int32_tが何なのかはstdint.hを見れば良いわけだけど、そういう.hを探すときはどうすればいいの?
A.
gcc -H ****.c (-Hオプション) を使うべし。
例えば以下のコードがあったとして、stdint.hのパスが知りたいとする。
[c] #include <stdint.h> int main(void){ int16_t a = 10; int32_t b = a; return 0; } [/c]
$gcc -H main.c . /usr/include/stdint.h .. /usr/include/features.h ... /usr/include/sys/cdefs.h (略)
おお!ちゃんと出た。そして中でincludeされてるのも辿ってくれるみたいだ。これは良い。
2.どう展開されているか
まあ***.hの絶対パスの取得方法は分かったよ。
Q.
でも実際は.hがどう展開されてるかも重要だよね。で、どうすればいいの?
A.
gcc -E ****.c (-Eオプション) を使うべし!
$gcc -E main.c (前略) typedef int int32_t; (後略)
おお!展開できとる!-Eはプリプロセッサ処理後のコードを表示するのね。
先生のアドバイスでは実際は検索のためにパイプでmoreとかlessに渡せとのこと。つまりgcc -E main.c | less、あとは検索ってことね。
3.絶対値を計算できない整数がある
8bit符号つき整数の表現範囲は127から-128です。
じゃあそこで「int8_t i1 = -128; i1 = -i1」ってすると、warning: this decimal constant is unsigned only in ISO C90が出るよ、とのこと。
Q.
自分の環境だとその警告でないんだけどなんで?
A.
環境が違うから。これが出るのはMacOS上のgccだとか。gccのバージョンも違うし出ないだろうとのこと。環境が変われば同じ.hでも#ifdefで取り込む内容は異なる。
ちなみに以下のコードのアセンブリコードを見ると
[c] #include <stdio.h> #include <stdint.h> int main(void){ int8_t i1 = -128; i1 = -i1; printf ("%d\n", i1); return 0; } [/c] movb $-128, -1(%rbp) negb -1(%rbp)
negb DESTはどうやらDESTの2の補数を求めてDESTに入れる命令みたい。
符号付き8bit整数で-128は1000 0000これを反転して0111 1111、で+1して2の補数を求めてやると答えは1000 0000。元と同じ。
実際出力結果は
$ ./a.out -128
なるほどね。
今日は色々と勉強になった1日でした。
コメントを残す