学部2年の授業と侮ることなかれ

金曜はアセンブリ言語の授業。

アセンブラは凄く苦手でそれほど好きじゃないんですが、やっぱり覚えておいた方がいいと思うので授業を受けることに。

少しだけわくわくしながら出席。

ところが今日はアセンブラというより単なる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日でした。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です