• 検索結果がありません。

C言語入門

N/A
N/A
Protected

Academic year: 2021

シェア "C言語入門"

Copied!
70
0
0

読み込み中.... (全文を見る)

全文

(1)

C言語入門

第5週

プログラミング言語Ⅰ(実習を含む。),

計算機言語Ⅰ・計算機言語演習Ⅰ,

(2)
(3)

Scratch

• グラフィカルに表現されたロジック使って、ブ

ロックを組む感覚でプログラムが作成出来る

http://scratch.mit.edu/

(4)

プログラミン

• 文部科学省による

Scratch に似たプログラミング環境

http://www.mext.go.jp/programin/

(5)

apt-cyg

• Cygwin用ソフトウェアパッケージ管理ツール

• パッケージが提供されているソフトに関しては

install サブコマンドで自動インストールが

可能(webを探し回る必要がない)。

• 使い方は help サブコマンド

• 例: diff コマンドのインストール

mintty + bash

(6)

apt-cyg と proxy の設定

• 学内から利用するにはproxyの設定が必要。apt-cyg

実行前に以下を mintty+bash へコピペして実行。

• 2014-05-06以降のversionはproxy自動検出対応済

upgrade-selfサブコマンドで一度apt-cyg自信をバー

ジョンアップしておけば以降proxyの設定は不要。

mintty + bash mintty + bash export ftp_proxy=http://proxy.cc.yamaguchi-u.ac.jp:8080/ export http_proxy=http://proxy.cc.yamaguchi-u.ac.jp:8080/ export https_proxy=http://proxy.cc.yamaguchi-u.ac.jp:8080/

apt-cyg upgrade-self

(7)

diff のインストール

• mintty+bash から以下のコマンドを実行

mintty + bash

(8)

diff

• UNIX系のファイル比較コマンド

mintty + bash

$ diff wavtest.c,20140410_211536.c wavtest.c

56c56

< double dt = 1.0 / 22050.0;

---

> double dt = 1.0 / SampleRate;

58c58

< v = INT16_MAX * sin(M_TWOPI * 1 * f * dt * i) * 0.05;

---

> v = INT16_MAX * sin(M_TWOPI * f * dt * i) * 0.05;

(9)

diff

• 並列表示

• --side-by-sideオプションによる比較

(10)

fc

• Windows 標準添付のファイル比較コマンド

コマンドプロンプト >fc wavtest.c,20140410_211536.c wavtest.c ファイル wavtest.c,20140410_211536.c と WAVTEST.C を比較しています ***** wavtest.c,20140410_211536.c double f = pow(2.0, (d - 69.0) / 12.0) * 440.0; double dt = 1.0 / 22050.0;

for (i = 0; i < NumSamples; i++) {

v = INT16_MAX * sin(M_TWOPI * 1 * f * dt * i) * 0.05; for (j = 0; j < NumChannels; j++) {

***** WAVTEST.C

double f = pow(2.0, (d - 69.0) / 12.0) * 440.0; double dt = 1.0 / SampleRate;

for (i = 0; i < NumSamples; i++) {

v = INT16_MAX * sin(M_TWOPI * f * dt * i) * 0.05; for (j = 0; j < NumChannels; j++) {

(11)

WinMerge

• GUIによるテキストファイルの比較ツール

• 相違点の合成も出来る

(12)

Rekisa

• GUIによる複数テキストファイルの比較ツール

(13)

パイプライン

• 書式: コマンド1 | コマンド2

• コマンド1の出力をコマンド2の入力に繋ぐ

• コマンド2実行時にキーボードを打ってコマンド1

の出力と全く同じ内容を入力したのと同じ効果を

得る。

• 例:

mintty + bash

echo 2014 | ./a

コマンドプロンプト

echo 2014 | is_leap_year_1_1

(14)

入力のリダイレクト

• 書式: コマンド < ファイル

• ファイルの内容をコマンドの入力に繋ぐ

• コマンド実行時にキーボードを打ってファイルの

内容と全く同じ内容を入力したのと同じ効果を得

る。

• 例:

mintty + bash

./a < test1_input.txt

コマンドプロンプト

is_leap_year_1_1 < test1_input.txt

test1_input.txt

2014

(15)

出力のリダイレクト

• 書式: コマンド > ファイル

• コマンドの出力をファイルに繋ぐ

• コマンド実行時の出力をファイルに保存出来る。

• 例:

mintty + bash

./a > test1_result.txt

コマンドプロンプト

is_leap_year_1_1 > test1_result.txt

(16)

ファイル比較コマンドを用いた

動作テストの自動化

1. テスト用の入力と期待する出力を用意する

2. テスト用の入力を与えて出力結果得る

mintty + bash

./a < test1_input.txt > test1_result.txt

コマンドプロンプト

is_leap_year_1_1 < test1_input.txt > test1_result.txt

test1_input.txt

2014

test1_expect.txt

(17)

テキスト比較ツールを用いた

動作テストの自動化

3. 期待する出力と実際の出力を比較する

mintty + bash

diff test1_expect.txt test1_result.txt

コマンドプロンプト

(18)

シェルスクリプト、バッチファイル

• コマンドを入力する代わりに、事前にファイル

に書いておいた一連のコマンドを実行出来る。

test_all.sh

#!/usr/bin/env bash

./a < test1_input.txt > test1_result.txt && diff test1_expect.txt test1_input.txt ./a < test1_input.txt > test2_result.txt && diff test2_expect.txt test2_input.txt ./a < test1_input.txt > test3_result.txt && diff test3_expect.txt test3_input.txt # ...

./a < test1_input.txt > test9_result.txt && diff test9_expect.txt test9_input.txt

test_all.bat

@ECHO OFF

is_leap_year_1_1 < test1_input.txt > test1_result.txt && fc test1_expect.txt test1_result.txt is_leap_year_1_1 < test2_input.txt > test2_result.txt && fc test2_expect.txt test2_result.txt is_leap_year_1_1 < test3_input.txt > test3_result.txt && fc test3_expect.txt test3_result.txt REM ...

(19)

テキスト比較ツールを用いた

動作テストの自動化

• シェルスクリプトによる一括テスト

mintty + bash

sh test_all.sh

test_all.sh #!/usr/bin/env bash

./a < test1_input.txt > test1_result.txt && diff test1_expect.txt test1_input.txt ./a < test1_input.txt > test2_result.txt && diff test2_expect.txt test2_input.txt ./a < test1_input.txt > test3_result.txt && diff test3_expect.txt test3_input.txt # ...

./a < test1_input.txt > test9_result.txt && diff test9_expect.txt test9_input.txt

mintty + bash

chmod +x

./test_all.sh

chmod コマンドで 実行ビットをセット(+x)すると 直接実行もできる

(20)

テキスト比較ツールを用いた

動作テストの自動化

• バッチファイルによる一括テスト

コマンドプロンプト

test_all.bat

test_all.bat @ECHO OFF

is_leap_year_1_1 < test1_input.txt > test1_result.txt && fc test1_expect.txt test1_result.txt is_leap_year_1_1 < test2_input.txt > test2_result.txt && fc test2_expect.txt test2_result.txt is_leap_year_1_1 < test3_input.txt > test3_result.txt && fc test3_expect.txt test3_result.txt REM ...

(21)
(22)

じゃんけん

日本語

• じゃんけんぽん!

• ぐー

• ちょき

• ぱー

English

• One, two, three, go!

• Stone

• Scissors

• Paper

(23)

じゃんけん

• 入力

• キーボードから以下の文字を入力

• "m" : グー

• "v" : チョキ

• "w" : パー

• 出力

• CPU の手を生成して勝敗判定

• 勝ち、負け、引き分けを表示

(24)

じゃんけん

• CPUの手の生成とプレイヤーの手の入力と

stone-scissors-paper1.c

#define frand() (rand() / (RAND_MAX + 1.0))

char hand_str[] = {'m', 'v', 'w'};

int cpu;

int you;

printf("'m': stone, 'v': scissors, 'w': paper¥n");

printf("One, two, three, go!¥n");

printf("You : ");

srand(time(NULL));

cpu = frand() * 3.0;

you = getchar();

printf("CPU : %c¥n", hand_str[cpu]);

疑似乱数を用いて 0以上3未満の 整数を生成 実行毎に異なる値を 得るための 疑似乱数の初期化

(25)

じゃんけん

• プレイヤーの手を数値に変換

stone-scissors-paper1.c

enum hand_enum {stone, scissors, paper};

// ...

switch (you) {

case 'm': you = stone; break;

case 'v': you = scissors; break;

case 'w': you = paper; break;

default:

printf("Your hand is invalid.¥n");

return EXIT_FAILURE;

}

switch 文では

break が重要。

break がない場合

次の条件用の処理も

続けて実行する。

試に break を

削って実行してみると

どうなるか?

列挙定数

stone = 0

scissors = 1

paper = 2

となっている

(26)

じゃんけん

• 勝敗の判定

stone-scissors-paper1.c switch (cpu) { case stone: switch (you) {

case stone: printf("Draw game.¥n"); break; case scissors: printf("You lose.¥n"); break; case paper: printf("You win.¥n"); break; }

break; // ~中略~ case paper:

switch (you) {

case stone: printf("You lose.¥n"); break; case scissors: printf("You win.¥n"); break; case paper: printf("Draw game.¥n"); break; }

break; default:

printf("CPU hand is invalid.¥n"); return EXIT_FAILURE; }

switch 文では

break が重要。

break がない場合

次の条件用の処理も

続けて実行する。

試に break を

削って実行してみると

どうなるか?

(27)

定数

• リテラル

• 数値リテラル

• 文字列リテラル

(28)

列挙(enumeration)

列挙子(enumerator)

• 書式:

• enum 列挙名 {列挙定数名 [= 定整数値], ...}

• 値を設定しないと

• 0から開始

• 前の値から+1ずつ増加

• #define の代わりに使える

(29)

列挙(enumeration)

列挙子(enumerator)

• 例:

enum boolean {NO, YES};

enum escape {

BELL = '¥a',

BACKSPACE = '¥b',

TAB = '¥t',

NEWLINE = '¥n',

VTAB = '¥v',

RETURN = '¥r'};

enum month {

JAN = 1, FEB, MAR,

APR, MAY, JUN,

JUL, AUG, SEP,

OCT, NOV, DEC};

NO = 0 YES = 1 JAN = 1 FEB = 2 MAR = 3 ... DEC = 12

(30)

列挙(enumeration)

列挙子(enumerator)

• #define で書き変えた場合の例:

#define NO 0

#define YES 1

#define BELL '¥a'

#define BACKSPACE '¥b'

#define TAB '¥t'

#define NEWLINE '¥n'

#define VTAB '¥v'

#define RETURN '¥r'

#define JAN 1

#define FEB 2

#define MAR 3

// ...

#define DEC 12

(31)

列挙(enumeration)

列挙子(enumerator)

• stone-scissors-paper1.c の例

stone-scissors-paper1.c

enum hand_enum {stone, scissors, paper};

// ...

switch (you) {

case 'm': you = stone; break;

case 'v': you = scissors; break;

case 'w': you = paper; break;

default:

printf("Your hand is invalid.¥n");

return EXIT_FAILURE;

}

stone = 0

scissors = 1

paper = 2

となっている

(32)

乱数: ランダムな数値を得る

• rand 関数

:

疑似乱数整数の生成

• srand 関数

:

疑似乱数系列の初期化

• time 関数

:

現在時刻の取得

毎回違う値を得るため

乱数系列初期化に用いる

(33)

rand 関数

• int rand(void)

• [0:RAND_MAX]の範囲で整数の疑似乱数を返す

• 戻り値:

• 疑似乱数の整数を返す

• 値の範囲は 0 以上 RAND_MAX 以下

• RAND_MAX は stdlib.h で定義されている

• RAND_MAX は少なくとも 32767 以上である

• RAND_MAX + 1 はオーバーフローするかもしれ

ない

JM / rand(3)

(34)

srand 関数

• void srand(unsigned int seed)

• 疑似乱数系列の初期化を行う

• 引数:

• seed: 疑似乱数の新しい系列の種

初期値は1

• 同じ種からは毎回同じ疑似乱数系列が生成

される。

JM / rand(3)

(35)

疑似乱数とは?

• 演算で生成する疑似的な乱数

• POSIX 1003.1-2003 で挙げられている実装例

static unsigned long next = 1;

/* RAND_MAX を 32767 と仮定 */

int myrand(void) {

next = next * 1103515245 + 12345;

return((unsigned)(next/65536) % 32768);

}

void mysrand(unsigned int seed) {

next = seed;

}

計算式は決まっているので、 同じseedなら 毎回同じ計算になるため 毎回同じ乱数系列が生成される

(36)

乱数系列の確認

• seed の値で乱数系列がどうなるか確認

randtest.c

int seed, i;

printf("seed = ");

scanf("%d", &seed);

srand(seed);

printf("RAND_MAX: %.0f¥n", (double) RAND_MAX);

for (i = 0; i < 10; i++) {

printf("%.0f¥n", (double) rand());

}

(37)

実行毎に異なる乱数系列に初期化

• stone-scissors-paper1.c の例

stone-scissors-paper1.c

#define frand() (rand() / (RAND_MAX + 1.0))

char hand_str[] = {'m', 'v', 'w'};

int cpu;

int you;

printf("'m': stone, 'v': scissors, 'w': paper¥n");

printf("One, two, three, go!¥n");

printf("You : ");

srand(time(NULL));

cpu = frand() * 3.0;

you = getchar();

printf("CPU : %c¥n", hand_str[cpu]);

time関数は 現在時刻を返す関数なので 実行毎に異なる seed を与える事が出来る

(38)

time 関数

• time_t time(time_t *t)

• 現在時刻を UNIX time で得る

• 引数:

• t:

通常はNULLで良い

NULLでない場合*tにも戻り値を格納する

• 戻り値:

• 現在時刻を UNIX time で返す。

JM / time(2)

(39)

UNIX time (UNIX時間、UNIX時刻)

• UNIX epoch (UNIX 紀元)

• 1970-01-01 00:00:00 UTC

• UNIX time

• UNIX epoch からの経過秒数

2038年問題

• 2038-01-19 03:14:07 UTC

= UNIX time: 2,147,483,647秒

= UNIC time: 0x7fffffff秒

• time_tが符号付き32bitの環境でオーバーフロー

EppochConverter

(40)

2038年問題

• 2038-01-19 03:14:07 UTC

= UNIX time: 2,147,483,647秒

= UNIC time: 0x7fffffff秒

• time_t が符号付き 32bit の環境

• time_t がオーバーフロー

• 以降、正しい日時が処理できなくなる!

• 対策

• time_t の 64bit 化等の対応が必要

(41)

未対策の環境はあるのか?

• SOURCEFORGE.JP MAGAZINE / 2014-05-02:

2038年問題に対応した「OpenBSD 5.5」リリース

http://sourceforge.jp/magazine/14/05/02/160000

• OpenBSD はセキュリティ面で非常に定評のある OS

• そんな OS でもつい最近になってようやく対応してい

る状況もある。

(42)

time_t の確認

• 0x7fffffff秒,0x80000000秒,-1秒を確認

time_t_test.c char buf[1024]; time_t t = 0x7fffffff; struct tm *tm; printf("sizeof(time_t): %d¥n", sizeof(time_t));

printf("time_t has sign: %s¥n", (~(time_t) 0) < (time_t) 0 ? "YES" : "NO");

tm = gmtime(&t);

strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm);

printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf);

t++;

tm = gmtime(&t);

strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm);

printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf);

t = -1;

tm = gmtime(&t);

strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm);

(43)

strftime 関数

• size_t strftime(char *s, size_t max,

const char *format,

const struct tm *tm)

• 日付と時刻を文字列に変換する

• 引数:

• s:

変換結果の格納先(通常はchar型配列)

• max: sのサイズ

• format: 変換の書式

• tm:

time_t 型の値をlocaltime関数または

gmtime関数を用いて変換した日付と時刻情報

• 戻り値:

• 終端文字列'¥0'を含めた変換結果のサイズ

• 格納先のサイズが不足していた場合は0

JM / strftime(3) JM / ctime(3)

(44)

各環境のtime_tの状況

Cygwin64 + GNU C

$ gcc time_t_test.c && ./a sizeof(time_t): 8

time_t has sign: YES

2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: 2147483648L: 2038-01-19 03:14:08 UTC 18446744073709551615UL: -1L: 1969-12-31 23:59:59 UTC

Cygwin32 + GNU C

$ gcc time_t_test.c && ./a sizeof(time_t): 4

time_t has sign: YES

2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 1901-12-13 20:45:52 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

(45)

各環境のtime_tの状況

Borland C++ 5.5.1

>bcc32 time_t_test.c && time_t_test

Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland time_t_test.c:

Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland sizeof(time_t): 4

time_t has sign: YES

2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 2106-02-06 06:28:15 UTC

(46)

各環境のtime_tの状況

Visual Studio 2013 Express Desktop Windows 32bit版

>cl time_t_test.c && time_t_test

Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved.

time_t_test.c

Microsoft (R) Incremental Linker Version 12.00.21005.1

Copyright (C) Microsoft Corporation. All rights reserved.

/out:time_t_test.exe time_t_test.obj

sizeof(time_t): 8 time_t has sign: YES

2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

VC は long が 32bit だったので 64bit 表示出来てない点には注意

(47)

各環境のtime_tの状況

Visual Studio 2013 Express Desktop Windows 64bit版

>cl time_t_test.c && time_t_test

Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64 Copyright (C) Microsoft Corporation. All rights reserved.

time_t_test.c

Microsoft (R) Incremental Linker Version 12.00.21005.1

Copyright (C) Microsoft Corporation. All rights reserved.

/out:time_t_test.exe time_t_test.obj

sizeof(time_t): 8 time_t has sign: YES

2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

VC は long が 32bit だったので 64bit 表示出来てない点には注意

(48)

[0:1) の実数の乱数生成法

• rand(): [0:RAND_MAX]の整数の乱数を生成

• [0:1) を得るには?

• 実数にして RAND_MAX + 1 で割れば良い

• RAND_MAX って幾つ?

• RAND_MAX + 1 だとオーバーフローするかも?

• RAND_MAX + 1.0 なら大丈夫

#define frand() (rand() / (RAND_MAX + 1.0))

暗黙の算術変換により

全てdoubleに型変換されて 計算される。

(49)

暗黙の算術変換 (概略)

• 二項演算子の両辺が異なる型の場合

以下のルールで変換(符号ありの場合)

• 片方がlong double: 他方をlong doubleに変換

• 片方がdouble: 他方を doubleに変換

• 片方がfloat: 他方をfloatに変換

• char, shortをintに変換

(50)

[0:N-1]の整数の乱数生成法

• [0:1) の実数の乱数を生成してNを掛けた後

整数に変換する

int x;

x = frand() * N;

なぜ以下の計算方法では駄目か? x = rand() / RAMD_MAX * N; x = rand() / RAMD_MAX * (N – 1); x = frand() * (N – 1); ヒント: • 生成される値の範囲は? • N が出る確率は? [0:N-1] の整数の乱数 = [0:N) の整数の乱数

(51)

任意の範囲の乱数整数

• stone-scissors-paper1.c の例

stone-scissors-paper1.c

#define frand() (rand() / (RAND_MAX + 1.0))

char hand_str[] = {'m', 'v', 'w'};

int cpu;

int you;

printf("'m': stone, 'v': scissors, 'w': paper¥n");

printf("One, two, three, go!¥n");

printf("You : ");

srand(time(NULL));

cpu = frand() * 3.0;

you = getchar();

printf("CPU : %c¥n", hand_str[cpu]);

[0:2] の乱数整数の生成

(52)

N面体のサイコロ

• [1:N] の整数が等確率で欲しい

int x;

x = frand() * N + 1;

[1:N] の整数の乱数 = [0:N-1] + 1 の整数の乱数 = [0:N) + 1 の整数の乱数

(53)

教科書の例

• 実は間違っている

test_p322.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define RANGE_MIN 0 #define RANGE_MAX 10 void main() { int rand10; // 0以上未満 srand( (unsigned)time(NULL) );

rand10=(int)(((double) rand() / (double) RAND_MAX) * RANGE_MAX + RANGE_MIN); printf("求まった乱数は %d¥n", rand10); } 0~9 までは (RAND_MAX / 10) / (RAND_MAX + 1) の確率で出現するので 0以上10以下の乱数を意図したとしても 出現確率のバランスが悪い rand() は 0 以上 RAND_MAX 以下 の値を返すので、この実装では 1/(RAND_MAX+1) の確率で 10 が出現してしまう ここのコメントも おかしいが、 0以上10未満でも 0以上10以下でも やってはいけない実装 乱数に関してよく見られる 有名な間違いです。

(54)

もっと質の良い疑似乱数

• random 関数 (POSIX.1-2001.)

• 非線形加法フィードバック

• JM /

random

(3)

• drand48 関数 (POSIX.1-2001.)

• 線形合同法+48bit整数

• JM /

drand48

(3)

• メルセンヌツイスタ

• Wikipedia /

メルセンヌツイスタ

(55)

getchar 関数

• int getchar(void)

• 入力 stream から1文字読み込む

• stream というのはバッファのようなもの

• 通常はENTERが押されるまで入力streamには値

が入って来ない。入力ストリームに値がない場合

は値が入ってくるまで待機する

• 戻り値:

• 入力された文字の文字コード返す

• ファイル終端やエラーの場合はEOFを返す

JM / fgetc(3)

(56)

getchar 関数の動作

• ENTERが押されるまで一気に読み込む

getchartest.c

#include <stdio.h>

#include <stdlib.h>

int main()

{

int c;

while ((c = getchar()) != EOF) {

printf("%#04x¥n", c);

}

return EXIT_SUCCESS;

}

バッファリングと言います。 読み込み処理を 高速化するための仕組みです。 バッファリングに溜めてある 入力文字を1文字ずつ取り出します。 バッファが空になると ENTERが押されるまで 入力待ちの状態になります。

(57)

tty_getkey

• ENTER待ちなしのキーボード入力

tty_getkey_example1.c #include "tty_getkey.h" #include "msleep.h" int main() { int c; tty_begin(); // 開始処理 while(tty_iskeyhit() == 0) { // 打鍵待ちループ msleep(1); // CPU に負荷をかけずに 1 msec 待つ

// tty_ishitkey() は即座に値を返すので空ループだと CPU に負荷がかかる }

c = tty_getkey(); // 打鍵キーの取得

tty_printf("%#x key was hit.¥n", c); // tty 用の printf tty_printf("Hit ESC key to exit.¥n");

while(KEY_ESC != tty_getkey()) { // 打鍵待ちループ ; // tty_ketkey()はキー入力があるまで待機するため空ループでも CPU に負荷をかけない } tty_end(); // 終了処理 return EXIT_SUCCESS; }

(58)

tty_getkey

• ENTER待ちなしのキーボード入力

• Windows 系の環境

• conio.h ライブラリを利用

• embarcadero / RAD Studio /

conio.h

• MSDN /

Console and Port I/O

• UNIX 系の環境

• curses ライブラリを利用

(59)

tty_getkey を利用したプログラムの

コンパイル

• サンプルプログラム

• tty_getkey_example1.c : サンプルプログラム本体

• 必要なファイル

• msleep.h

: ミリ秒 sleep 用ヘッダ

• tty_getkey.h

: tty_getkey ヘッダファイル

• tty_getkey.c

: tty_getkey 本体

mintty + bash + GNU C

$ gcc tty_getkey_example1.c tty_getkey.c -lcurses

コマンドプロンプト + Borland C++

(60)

tty_getkey 利用前の準備

Cygwin の場合

• ncurses の開発用ライブラリが必要

• 以下のコマンドを入力してインストール

• Borland C++ は、標準添付の conio というライ

ブラリを使っているので前準備は不要

Cygwin64 mintty + bash

apt-cyg install libncursesw-devel

Cygwin32 mintty + bash

(61)

Cygwinが何bit版か確認する方法

• uname コマンドに -a オプションを付けて実行

Cygwin64 mintty + bash

$ uname -a

CYGWIN_NT-6.1 EX58EXTREME 1.7.27(0.271/5/3) 2013-12-09 11:54 x86_64 Cygwin

Cygwin32 mintty + bash

$ uname -a

CYGWIN_NT-6.1-WOW64 EX58EXTREME 1.7.27(0.271/5/3) 2013-12-09 11:57 i686 Cygwin

i686 なら 32bit 版 x86_64 なら 64bit 版

(62)

tty_getkey 初期化関数

• int tty_begin(void)

• tty_getkey の初期化処理を行います

• int tty_end(void)

(63)

tty_getkey キー待ち受け関数

• int tty_iskeyhit(void)

• キー入力の有無を調べます。

• キー入力があれば 1 なければ 0 を返します。

• int tty_getkey(void)

• キー入力を取得します。キー入力がない場合、キー

入力が発生するまで待機します。

• 通常のキーは'a'や'A'等の文字コードを返します。

• 特殊キーの場合はKEY_UPやKEY_DOWN等のマクロで

定義されたキーコードを返します。

(64)

tty_getkey() が返すキーコード

• KEY_INSERT

• KEY_DELETE

• KEY_HOME

• KEY_END

• KEY_PAGEUP

• KEY_PAGEDOWN

• KEY_UP

• KEY_DOWN

• KEY_LEFT

• KEY_RIGHT

• KEY_ESC

• KEY_TAB

• KEY_SPACE

• KEY_BS

• KEY_ENTER

• KEY_F1 ~ KEY_F48

通常のキーは 'a', 'A' 等の

文字定数リテラルが対応

(65)

tty_getkey 出力関数

• int tty_printf(char *fmt, ....)

• 書式付の出力を行います。

• 画面制御を伴うためtty_begin()~tty_end()

の間では、通常のprintをは使わないでください。

• int tty_setxy(int x, int y)

(66)

tty_getkey 画面情報関数

• int tty_getx(void)

• カーソルの x 座標を返します。

• int tty_gety(void)

• カーソルの y 座標を返します。

• int tty_getw(void)

• カーソルが移動可能な画面の幅を返します。

• int tty_geth(void)

• カーソルが移動可能な画面の高さを返します。

(67)

tty_getkey_example2

• カーソルキーで移動、ESC キーで終了

• 移動した場所に * を表示する

(68)

tty_getkey_example2

tty_getkey_example2.c

while (KEY_ESC != (c = tty_getkey())) {

switch (c) {

case KEY_UP: y--; break;

case KEY_DOWN: y++; break;

case KEY_RIGHT: x++; break;

case KEY_LEFT: x--; break;

}

x = x < 1 ? 1 : w - 2 < x ? w - 2 : x;

y = y < 1 ? 1 : h - 2 < y ? h - 2 : y;

tty_setxy(0, 0);

tty_printf("(%2d,%2d) : %#06x", x, y, c);

tty_setxy(x, y);

tty_printf("*");

}

入力された カーソルキーの方向に応じて 座標を上下左右に移動 画面から はみ出さないように 移動範囲を制限

(69)

tty_getkey_example3

• 6面体サイコロの例

• 開始するとサイコロが転がり始める

• 何かキーを押すと3秒待って終了する

tty_getkey_example3.c

while(tty_iskeyhit() == 0) {

d = frand() * 6 + 1;

tty_setxy(0, 0);

tty_printf("%d", d);

msleep(1);

}

msleep(3000);

値域 [1:6] の乱数生成 = 6面体サイコロ

(70)

参考文献

• [1] B.W.カーニハン/D.M.リッチー著 石田晴久

訳、プログラミング言語C 第2版 ANSI 規格準

拠、共立出版(1989)

参照

関連したドキュメント

事前調査を行う者の要件の新設 ■

タップします。 6通知設定が「ON」になっ ているのを確認して「た めしに実行する」ボタン をタップします。.

パスワード 設定変更時にパスワードを要求するよう設定する 設定なし 電波時計 電波受信ユニットを取り外したときの動作を設定する 通常

トリガーを 1%とする、デジタル・オプションの価格設定を算出している。具体的には、クー ポン 1.00%の固定利付債の価格 94 円 83.5 銭に合わせて、パー発行になるように、オプション

(7)

出来形の測定が,必要な測 定項目について所定の測 定基準に基づき行われて おり,測定値が規格値を満 足し,そのばらつきが規格 値の概ね

サンプル 入力列 A、B、C、D のいずれかに指定した値「東京」が含まれている場合、「含む判定」フラグに True を

・ 化学設備等の改造等の作業にお ける設備の分解又は設備の内部 への立入りを関係請負人に行わせ