C言語入門
第15週
プログラミング言語Ⅰ(実習を含む。),
計算機言語Ⅰ・計算機言語演習Ⅰ,
補足
return 戻り値;
• 関数から抜けて呼び出し元へ戻り値を渡す
return_test1.c
int sub()
{
return 123;
printf("hello¥n");
}
void main()
{
int x = sub();
printf("%d¥n", x);
}
return文に与えた値が
関数の戻り値になり
演算に使用される
return文を実行すると
呼び出し元に戻るので
それ以降の文は
実行されない
mintty + bash + GNU C
$ gcc return_test1.c && ./a
123
return 文
• 戻り値の型は必要に応じて適切な型を選ぶ
return_test2.c
int sub()
{
return 1.23;
}
void main()
{
double = sub();
printf("%f¥n", x);
}
この例では戻り値の型はintなので
return文にdoubleを与えても
戻り値はint型にキャストされるので
整数になる
mintty + bash + GNU C
$ gcc return_test2.c && ./a
1.000000
例えばもし
浮動小数点数の値を
戻したいなら
戻り値の型は
doubleでないといけない
コマンドライン引数
• char *argv[] は char* 型の配列
mintty + bash
$ ./argtest a b "c d" "e¥"f"
argc = 5
argv[0] = "./argtest"
argv[1] = "a"
argv[2] = "b"
argv[3] = "c d"
argv[4] = "e"f"
'a' '¥0' 'b' '¥0' 'c' ' ' 'd' '¥0' 'e' '"'
f
'¥0'
argv[1]
argv[2]
argv[3]
argv[4]
正確には
関数の引数で最初の [] は
* と同じだったので
char *argv[] は
char **argv と同じ
つまり
char 型へのポインタへのポインタ
データ型の制限: <limits.h>
CHAR_BIT
char 型のビット数
CHAR_MAX
UCHAR_MAX または SCHAR_MAX
CHAR_MIN
0 または SCHAR_MIN
SCHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN
signed の char, short, int, long の最小値
SCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX
signed の char, short, int, long の最大値
UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX
unsigned の char, short, int, long の最大値
なお unsigned 型は負の数がないので最小値は 0 である
FLT_RADIX, DBL_RADIX
指数表現の基数
FLT_DIG, DBL_DIG
精度の10進桁数
FLT_MANT_DIG, DBL_MANT_DIG
仮数部における基数(RADIX)の桁数
FLT_EPSILON, DBL_EPSILON
1.0 + 𝑥 ≠ 1.0となる最小の𝑥
FLT_MAX, DBL_MAX
float, double の最大値
FLT_MIN, DBL_MIN
float, double の正規化された最小の浮動小数値
FLT_MAX_EXP, DBL_MAX_EXP
RADIX
𝑛− 1が表現可能な𝑛の最大値
FLT_MIN_EXP, DBL_MIN_EXP
10
𝑛を正規化された浮動小数値として表現可能な
𝑛の最小値
この授業で扱わなかったこと
• 構造体と共用体: struct, union
• 型定義: typedef
• 可変長引数: <stdarg.h>
• va_list, va_start, va_arg, va_end
• 非局所ジャンプ: <setjmp.h>
• シグナル処理: <signal.h>
分割コンパイル
• ファイルが多くなるとコンパイルが大変
10
mintty + bash + GNU C
$ gcc strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c $
cmd + Borland C++
>bcc32 strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
strtoi_test.c: strtoi.c: strtosign.c: strtobase.c: basetoint.c: base36toint.c:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
一度実行すれば
カーソルキーの上下で
コマンドの実行履歴から
選べるが、最初が面倒
1ファイルしか変更してないのに
全ファイルコンパイルし直すのは非効率
make コマンド
• 依存関係を記述し必要な処理だけ行う
• Makefile に依存関係と作成方法を記述する
Makefile.cygwin.strtoi_test,1
all: strtoi_test.exe
strtoi_test.exe: strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c $(CC) -o $@ $^
clean:
-rm strtoi_test.exe
Makefile.bcc32.strtoi_test
all: strtoi_test.exe
strtoi_test.exe: strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c $(CC) strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c clean:
-DEL strtoi_test.exe *.obj *.tds
作成するファイル: 材料のファイル ...
make コマンド
• make と打つだけで自動的にコンパイル
12
mintty + bash + GNU C
$ make -f Makefile.cygwin.strtoi_test,1
cc -o strtoi_test.exe strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c
cmd + Borland C++
>make -f Makefile.bcc32.strtoi_test
MAKE Version 5.2 Copyright (c) 1987, 2000 Borland
bcc32 strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36t oint.c
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland strtoi_test.c: strtoi.c: strtosign.c: strtobase.c: basetoint.c: base36toint.c:
make コマンド
• 依存関係の記述
Makefile.cygwin.strtoi_test,2
all: strtoi_test.exe
strtoi_test.exe: strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o $(CC) -o $@ $^
strtoi_test.o: strtoi_test.c myfunc_week10.h
strtoi.o: strtoi.c myfunc_week10.h myfunc_week11.h myfunc_week12.h strtosign.o: strtosign.c myfunc_week12.h
strtobase.o: strtobase.c myfunc_week12.h basetoint.o: basetoint.c myfunc_week11.h base36toint.o: base36toint.c myfunc_week11.h clean:
-rm strtoi_test.exe strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o
作成するファイル: 材料のファイル ...
タブ...→
作成方法
標準的な作成方法で良い場合は
作成方法は省略出来る
make コマンド
• 依存関係の解決
14
mintty + bash + GNU C
$ make -f Makefile.cygwin.strtoi_test,2 cc -c -o strtoi_test.o strtoi_test.c cc -c -o strtoi.o strtoi.c cc -c -o strtosign.o strtosign.c cc -c -o strtobase.o strtobase.c cc -c -o basetoint.o basetoint.c cc -c -o base36toint.o base36toint.c
cc -o strtoi_test.exe strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o $ make
make: Nothing to be done for 'all'. $ rm strtosign.o
$ make
cc -c -o strtosign.o strtosign.c
cc -o strtoi_test.exe strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o
直前に削除したため改めて
コンパイルが必要になった
ファイルだけ処理し直して
てくれている
コンパイルが完了しているので
改めてコンパイルする
必要がなかった
make コマンド
• 依存関係の解決
• 必要に応じて適宜作成方法を実行する
• 例:
• 材料のファイルが不足している場合
• 作成するファイル(旧)、材料のファイル(新)の場合
make コマンド
• 同じmakeという名前が付いていて基本は同じ
だが方言があり、細かい違いがある
• Wikipedia /
make
•
GNU Make
• Embarcadero /
MAKE
• JM /
make
(1)
• FreeBSD 9.0-RELEASE-K /
make
(1)
• MSDN /
NMAKE Reference
その他のビルドツール
• Autotools
• autoconf, automake, libtool の総称
• UNIX 系のソフトウェアでは標準的なビルドツール
• 以下の標準的な手順でビルド出来るようになる
• 書籍
• GNU AUTOCONF, AUTOMAKE, AND LIBTOOL
https://sourceware.org/autobook/
(無料オンライン版)
• Wikipedia /
Autotools
mintty + bash + GNU C
$ ./configure $ make
その他のビルドツール
• CMake -
http://www.cmake.org/
• マルチプラットフォームな Makefile 作成ツール
• Wikipedia /
CMake
ライブラリの自作
• 標準ライブラリ関数はアーカイブやライブラリ
と呼ばれる複数のオブジェクトファイルを1つ
にまとめたファイルとして提供されている
• cygwinでは/usr/lib/libc.a等
• Borland C++ではC:¥boland¥bcc32¥Lib¥cw32.lib等
• 標準ライブラリはコンパイル時に自動的にリ
ンクされる
• 但し <math.h> 等は -lm 等として明示的に
/usr/lib/libm.aをリンクする必要がある場合もある
ライブラリの自作
• 複数のオブジェクトファイルを1つのファイルにまとめる
にはアーカイバやライブラリアンと呼ばれるツールを
用いる
• JM /
ar
(1)
• 作成方法:
ar q ライブラリ名 オブジェクトファイル名 ...
• embarcadero /
ライブラリマネージャ TLIB.EXE
• 作成方法:
tlib ライブラリ名 -+オブジェクトファイル名 ...
20
ライブラリの自作(Cygwin)
• 複数のオブジェクトファイル(.oファイル)を1つ
の.aファイルにまとめる
• まとめたファイルをアーカイブ(archive)または
スタティックライブラリ(static library)と呼ぶ
mintty + bash + GNU C
$ gcc -c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c
$ ar q myfunc.a strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o ar: myfunc.a を作成しています $ gcc strtoi_test.c myfunc.a
必要な .o ファイルを
myfunc.a から探してリンクし
実行ファイルを作成
複数の .o ファイルをまとめた
.a ファイルの作成
ライブラリの自作(Borland C++)
• 複数のオブジェクトファイル(.objファイル)を1
つの.libファイルにまとめる
• まとめたファイルをライブラリと呼ぶ
22cmd + Borland C++
>bcc32 /c strtoi.c strtosign.c strtobase.cbasetoint.c base36toint.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
strtoi.c: strtosign.c: strtobase.c: basetoint.c: base36toint.c:
>tlib myfunc.lib -+strtoi.obj -+strtosign.obj -+strtobase.obj -+basetoint.obj -+base36toint.obj TLIB 4.5 Copyright (c) 1987, 1999 Inprise Corporation
>bcc32 strtoi_test.c myfunc.lib
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland strtoi_test.c:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
必要な .obj ファイルを
myfunc.lib から探してリンクし
実行ファイルを作成
複数の .o ファイルをまとめた
.lib ファイルの作成
ライブラリの自作
• make によるアーカイブの作成
Makefile.cygwin.myfunc.a
all: myfunc.a
myfunc.a: strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o $(AR) q $@ $^
strtoi_test.o: strtoi_test.c myfunc_week10.h
strtoi.o: strtoi.c myfunc_week10.h myfunc_week11.h myfunc_week12.h strtosign.o: strtosign.c myfunc_week12.h
strtobase.o: strtobase.c myfunc_week12.h basetoint.o: basetoint.c myfunc_week11.h base36toint.o: base36toint.c myfunc_week11.h clean:
ライブラリの自作
• make によるアーカイブの作成
24
mintty + bash + GNU C
$ make -f Makefile.cygwin.myfunc.a cc -c -o strtoi.o strtoi.c cc -c -o strtosign.o strtosign.c cc -c -o strtobase.o strtobase.c cc -c -o basetoint.o basetoint.c cc -c -o base36toint.o base36toint.c
ar q myfunc.a strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o ar: myfunc.a を作成しています
ユニットテスト(単体テスト)
• 標準ライブラリヘッダ <assert.h>
• assert マクロの利用
• ユニットテストツールの利用
• CUnit
http://cunit.sourceforge.net/
assert マクロ
void assert(int expression)
• expression がゼロの場合以下のメッセージを
stderr に出力し abort する
Assertion failed: expression, file filename, line nnn
• <assert.h>をインクルードする時点で NDEBUG
マクロが定義されていると assert マクロは無
視される
• ユニットテストだけでなくデバッグ時のみ有効に
する不正値のチェック等でも利用される
26assert マクロ
• 専用のテストルーチンで使用した例
is_leap_year_assert.c
void test_leap_year() { assert(is_leap_year(-400) == 1); assert(is_leap_year(- 56) == 1); assert(is_leap_year(- 4) == 1); assert(is_leap_year( 0) == 1); assert(is_leap_year( 4) == 1); assert(is_leap_year( 56) == 1); assert(is_leap_year( 400) == 1); assert(is_leap_year(1996) == 1); assert(is_leap_year(2000) == 1); assert(is_leap_year(2004) == 1); }is_leap_year_assert.c
void test_normal_year() { assert(is_leap_year(-300) == 0); assert(is_leap_year(-200) == 0); assert(is_leap_year(-100) == 0); assert(is_leap_year(- 3) == 0); assert(is_leap_year(- 2) == 0); assert(is_leap_year(- 1) == 0); assert(is_leap_year( 1) == 0); assert(is_leap_year( 2) == 0); assert(is_leap_year( 3) == 0); assert(is_leap_year( 100) == 0); assert(is_leap_year( 200) == 0); assert(is_leap_year( 300) == 0); assert(is_leap_year(1900) == 0); assert(is_leap_year(1997) == 0); assert(is_leap_year(1998) == 0); assert(is_leap_year(1999) == 0); assert(is_leap_year(2001) == 0); assert(is_leap_year(2002) == 0); assert(is_leap_year(2003) == 0); }is_leap_year_assert.c
int main() { test_leap_year(); test_normal_year(); return EXIT_SUCCESS; }assert マクロ
• 専用のテストルーチンで使用した例
• エラーがなければ何も起きない
• エラーがあるとそこで実行が中断する
28
mintty + bash + GNU C
mintty + bash + GNU C
$ gcc is_leap_year_assert.c is_leap_year_func_4_2.c && ./a
$ gcc is_leap_year_assert.c is_leap_year_func_4_2.c && ./a
assertion "is_leap_year( 0) == 1" failed: file "is_leap_year_assert.c", line 10, function: test_leap_year
CUnit
• 専用のテストルーチンを作成して使用
is_leap_year_cunit.c
void test_leap_year() { CU_ASSERT_EQUAL(is_leap_year(-400), 1); CU_ASSERT_EQUAL(is_leap_year(- 56), 1); CU_ASSERT_EQUAL(is_leap_year(- 4), 1); CU_ASSERT_EQUAL(is_leap_year(1996), 1); CU_ASSERT_EQUAL(is_leap_year(2000), 1); CU_ASSERT_EQUAL(is_leap_year(2004), 1); }is_leap_year_cunit.c
void test_normal_year() { CU_ASSERT_EQUAL(is_leap_year(-300), 0); CU_ASSERT_EQUAL(is_leap_year(-200), 0); CU_ASSERT_EQUAL(is_leap_year(-100), 0); CU_ASSERT_EQUAL(is_leap_year(- 3), 0); CU_ASSERT_EQUAL(is_leap_year(2002), 0); CU_ASSERT_EQUAL(is_leap_year(2003), 0); }is_leap_year_cunit.c
static CU_TestInfo test_is_leap_year[] = { {"leap year", test_leap_year},
{"normal year", test_normal_year}, CU_TEST_INFO_NULL,
};
static CU_SuiteInfo suites[] = {
{"is_leap_year test", NULL, NULL, test_is_leap_year}, CU_SUITE_INFO_NULL, }; int main() { CU_initialize_registry(); CU_register_suites(suites); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); CU_cleanup_registry(); return EXIT_SUCCESS; }
CUnit
• 専用のテストルーチンを作成して使用
• ユニットテストの達成状況がレポートされる
30
mintty + bash + GNU C
$ gcc is_leap_year_cunit.c is_leap_year_func_4_2.c -lcunit && ./a
CUnit - A unit testing framework for C - Version 2.1-2 http://cunit.sourceforge.net/
Suite: is_leap_year test Test: leap year ...passed Test: normal year ...passed
Run Summary: Type Total Ran Passed Failed Inactive suites 1 1 n/a 0 0 tests 2 2 2 0 0 asserts 29 29 29 0 n/a Elapsed time = 0.000 seconds