『本当は怖いC言語』を読んで
書名:『本当は怖いC言語』
著者:種田 元樹
(「本当は怖いC言語」サポートページ)
感想
C言語の特徴が分かり、2冊目の教科書に適している本です。
以下に参考になった記事・試したプログラムを、自分用のメモも兼ねて記載します。
P.63「スタートアップルーチンを見てみよう」
Cランタイムやlibcを使わないでC言語の実行ファイルを作成する記事で、アセンブリ言語が登場したことに驚きました。
#include <stdio.h> int main(int argc, char *argv[]) { return(0); } void _start(int args) { main(0, 0); asm("movl $0,%ebx\n" "movl $1,%eax\n" "int $0x80"); }
$ gcc -S test.c
$ gcc -c test.s
$ ld -nostdlib test.o
$ ./a.out
$ echo $?0
$ ldd a.out
動的実行ファイルではありません
P.249「printf()関数は「変換指定の変換」をすることができます」
printf("%0*d\n", 4, 10);
P.265
入力を伴うプログラムの、エラー処理勉強に良いサンプルコードがあります。
(BSD系OSでの入力待ち中にcontrol+D)
P.301「恐怖実験 定義済みdefineと変数名が被ったら」
#include <stdio.h> int main(int argc, char *argv[]) { char linux[16] = "define linux"; printf("%s\n", linux); return(0); }
$ gcc -g -Wall define.c
define.c: 関数 ‘main’ 内:
define.c:6:7: エラー: expected identifier or ‘(’ before numeric constant
define.c:8:2: 警告: 書式 ‘%s’ は引数の型が ‘char *’ であると予期されますが、第 2 引数の型は ‘int’ です [-Wformat]
P.361「ポインタにNULLを与えると」
“ぬるぽ”について。
P.375「Intel系のCPUはリトルエンディアン」
#include <stdio.h> int main(int argc, char *argv[]) { int i; int num = 2147483647; unsigned char *ptr; printf("num = %d\n", num); ptr = (unsigned char *) # for (i = 0; i < (int) sizeof(num); i++) { printf("0x%X ", *ptr); ptr++; } printf("\n"); return(0); }
$ gcc -g -Wall little_endian.c
$ ./a.out
num = 2147483647
0xFF 0xFF 0xFF 0x7F
$ echo "ibase=10; obase=16; 2147483647" | bc
7FFFFFFF
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 37
model name : Intel(R) Pentium(R) CPU G6950 @ 2.80GHz
~略~
P.378「ポインタ変数に〜略〜文字列定数のアドレスを代入して初期化」
文字列定数は多くのシステムでは書込み禁止エリアに確保されている。
#include <stdio.h> int main(int argc, char *argv[]) { char *test = "heyhey\n"; test[0] = 'H'; printf("%s", test); return(0); }
$ gcc -g -Wall ptr_const.c
$ ./a.out
Segmentation fault
P.419「アラインメントを意識する理由」
構造体の宣言の並び方を変えるだけで、効率的にメモリが利用できるようになる。
P.432「13.3 ビット単位の変数が扱えるビットフィールド」
やっと理解できた気がします。
P.524「ポインタ変数や、ポインタ型のメンバ変数は面倒でも = NULL で初期化」
0をNULLとして扱っていないコンピュータがある。
以上。