Presentation is loading. Please wait.

Presentation is loading. Please wait.

プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)

Similar presentations


Presentation on theme: "プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)"— Presentation transcript:

1 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
C言語入門 第3週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)

2 先週の復習1

3 各データ型のサイズ(1/4) sizeoftest.c による比較 32bit版Cygwin+gcc 64bit版Cygwin+gcc
$ gcc sizetest.c && ./a char: wchar_t: shor: int: long: long long: 8 float: double: long double: 12 $ gcc sizetest.c && ./a char: wchar_t: shor: int: long: long long: 8 float: double: long double: 16 コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

4 各データ型のサイズ(2/4) sizeoftest.c による比較 Borland C++ 5.5 コンパイルする環境により
>bcc32 sizeoftest.c && sizeoftest Borland C for Win32 Copyright (c) 1993, 2000 Borland sizeoftest.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland char: wchar_t: shor: int: long: float: double: long double: 10 コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

5 各データ型のサイズ(3/4) sizeoftest.c による比較
Visual Studio 2013 Express Desktop Windows 32bit版 >cl sizeoftest.c && sizeoftest Microsoft(R) C/C++ Optimizing Compiler Version for x86 Copyright (C) Microsoft Corporation. All rights reserved. sizeoftest.c Microsoft (R) Incremental Linker Version /out:sizeoftest.exe sizeoftest.obj char: wchar_t: shor: int: long: long long: 8 float: double: long double: 8 コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

6 各データ型のサイズ(4/4) sizeoftest.c による比較
Visual Studio 2013 Express Desktop Windows 64bit版 >cl sizeoftest.c && sizeoftest Microsoft(R) C/C++ Optimizing Compiler Version for x64 Copyright (C) Microsoft Corporation. All rights reserved. sizeoftest.c Microsoft (R) Incremental Linker Version /out:sizeoftest.exe sizeoftest.obj char: wchar_t: shor: int: long: long long: 8 float: double: long double: 8 コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

7 データ型のサイズ C99における解決方法 stdint.h ヘッダファイルを使う #include <stdint.h>
補足 データ型のサイズ C99における解決方法 stdint.h ヘッダファイルを使う 第1週のサンプルプログラム wavtest.c bmptest.c でも使っています。 #include <stdint.h> // ... int8_t i8; // 符号付き 8bit整数 uint8_t ui8; // 符号なし 8bit整数 int16_t i16; // 符号付き16bit整数 uint16_t ui16; // 符号なし16bit整数 int32_t i32; // 符号付き32bit整数 uint32_t ui32; // 符号なし32bit整数 int64_t i64; // 符号付き64bit整数 uint64_t ui64; // 符号なし64bit整数 注: Boarland C は C99 非対応なので stdint.h が使えない。

8 変数と定数

9 変数の割り当てとバイトオーダー 32bit int型の場合 int a; // 変数の宣言 : 0x?? 0x~00 0x?? 0x~01

10 変数の割り当てとバイトオーダー 32bit int型の場合(Little Endian) int a = 0x12345678;
Intel の x86 系 CPU 等 32bit int型の場合(Little Endian) : int a = 0x ; // 変数の宣言と初期化 0x78 0x~00 0x56 0x~01 32bit 0x34 0x~02 0x12 0x~03 0x?? 0x~04 0x?? 0x~05 0x?? 0x~06 a 0x 0x?? 0x~07 0x?? 0x~08 :

11 変数の割り当てとバイトオーダー 32bit int型の場合(Big Endian) int a = 0x12345678;
ネットワーク上を流れるデータ等 32bit int型の場合(Big Endian) : int a = 0x ; // 変数の宣言と初期化 0x12 0x~00 0x34 0x~01 32bit 0x56 0x~02 0x78 0x~03 0x?? 0x~04 0x?? 0x~05 0x?? 0x~06 a 0x 0x?? 0x~07 0x?? 0x~08 :

12 変数の割り当てとバイトオーダー 16bit short型の場合(Little Endian) short a = 0x1234;
Intel の x86 系 CPU 等 16bit short型の場合(Little Endian) : short a = 0x1234; // 変数の宣言と初期化 0x34 0x~00 16bit 0x12 0x~01 0x?? 0x~02 a 0x1234 0x?? 0x~03 0x?? 0x~04 0x?? 0x~05 同じ場所から32bitで取ると 0x?? 0x~06 a 0x????1234 0x?? 0x~07 0x?? 0x~08 :

13 変数の割り当てとバイトオーダー 16bit short型の場合(Big Endian) short a = 0x1234;
ネットワーク上を流れるデータ等 16bit short型の場合(Big Endian) : short a = 0x1234; // 変数の宣言と初期化 0x12 0x~00 16bit 0x34 0x~01 0x?? 0x~02 a 0x1234 0x?? 0x~03 0x?? 0x~04 0x?? 0x~05 同じ場所から32bitで取ると 0x?? 0x~06 a 0x1234???? 0x?? 0x~07 0x?? 0x~08 :

14 バイトオーダーに関する注意点 ファイル保存時に注意が必要 以下のコードはファイルに保存した値が実行環境により異なるかも?
int32_t a = 0x ; // ... fwrite(&a, sizeof(a), 1, fp); 例: 第1週のサンプルプログラム wavtest.c bmptest.c Little Endian の環境では正常に動くが Big Endian の環境では正常に動かない!

15 バイトオーダーに関する注意点 正常な動作の例 a 0x12345678 a 0x12345678 ファイルへ 書き込み ファイルから
読み込み 0x78 0x56 0x34 0x12 Little Endian の PC Little Endian の PC

16 バイトオーダーに関する注意点 不具合の例 a 0x12345678 a 0x78563412 ファイルへ 書き込み ファイルから 読み込み
Little Endian の PC Big Endian の PC

17 バイトオーダーに関する注意点 不具合の例 a 0x12345678 a 0x78563412 ファイルへ 書き込み ファイルから 読み込み
Big Endian の PC Little Endian の PC

18 バイトオーダーの解決方法の例 ビット演算を利用 1バイトずつに切り分けてファイルへ保存する int32_t a = 0x12345678;
// ... fputc((a ) & 0xFF, fp); fputc((a >> 8) & 0xFF, fp); fputc((a >> 16) & 0xFF, fp); fputc((a >> 24) & 0xFF, fp); 絶対に Little Endian で 書き込むことが出来る。

19 バイトオーダーの解決方法の例 よく使う処理は関数にしてまとめる 再利用し易くなる 教科書 pp.149-206.
int fputle32(int32_t a) { int r; r = fputc((a ) & 0xFF, fp); if (r == EOF) return EOF; r = fputc((a >> 8) & 0xFF, fp); if (r == EOF) return EOF; r = fputc((a >> 16) & 0xFF, fp); if (r == EOF) return EOF; r = fputc((a >> 24) & 0xFF, fp); if (r == EOF) return EOF; return 4; }

20 バイトオーダーの解決方法の例 バイトオーダーを考慮したライブラリを使う
SDL (Simple DirectMedia Layer) ライブラリ SDL_SwapBE32 関数 SDL_SwapLE32 関数 int32_t a = 0x ; Uint32 x = SDL_SwapLE32(a); // ... fwrite(&x, sizeof(x), 1, fp); 絶対に Little Endian で 書き込むことが出来る。

21 fwrite 関数 引数: 戻り値: BUF: 保存するデータへのポインタ SIZE: 1要素当りのサイズ COUNT: 保存する要素数
size_t fwrite(const void *BUF, size_t SIZE, size_t COUNT, FILE *fp); 引数: BUF: 保存するデータへのポインタ SIZE: 1要素当りのサイズ COUNT: 保存する要素数 fp: ファイル構造体へのポインタ 戻り値: 書き込んだ要素数 正常終了の場合COUNTに同じ

22 fputc 関数 引数: 戻り値: c: 書き込む文字 fp: ファイル構造体へのポインタ 書き込んだ文字c エラーの場合EOF
int fputc(int c, FILE *fp); 引数: c: 書き込む文字 fp: ファイル構造体へのポインタ 戻り値: 書き込んだ文字c エラーの場合EOF

23 値の表示

24 値の表示 printf関数を使う printftest.c いろんな値を表示できる。 #include <stdio.h>
教科書 pp.61, 64-66, 98. 値の表示 printf関数を使う printftest.c #include <stdio.h> #include <stdlib.h> int main() { int i = 128; double d = 123e-3; char s[] = "hello, world"; printf("i = %d\n", i); printf("d = %f\n", d); printf("s = %s\n", s); return EXIT_SUCCESS; } いろんな値を表示できる。 $ gcc printftest.c && ./a i = 128 d = s = hello, world

25 printf 関数 引数: 戻り値: FORMAT: 書式 ...: 任意の数の引数 書き出された文字数。 エラーの場合負の数。
教科書 pp.61, 64-66, 98. printf 関数 int printf(const char *FORMAT, ...); 引数: FORMAT: 書式 ...: 任意の数の引数 戻り値: 書き出された文字数。 エラーの場合負の数。 参考: [1] pp

26 printf: 書式 %~変換文字までをフィールドと呼ぶび、テンプレート(穴空き定規)ように扱われる フィールドは以下の要素から成る
教科書 pp.61, 64-66, 98. printf: 書式 %~変換文字までをフィールドと呼ぶび、テンプレート(穴空き定規)ように扱われる フィールドは以下の要素から成る %[フラグ][最小フィールド幅][.精度][長さ修飾子]変換文字 printf("1 + 2 = %d\n", 1 + 2); 1 + 2 = \n ここに、 int型の整数型データとして解釈した 2つ目の引数の値(上記の例では1+2の計算結果)を 符号付き10進数にして印字する 参考: [1] pp

27 printf: フラグ -: 左揃えで印字 +: 数を符号付きで印字 スペース: 最初の文字が符号でない場合スペースを前に付ける
教科書 pp.61, 64-66, 98. printf: フラグ -: 左揃えで印字 +: 数を符号付きで印字 スペース: 最初の文字が符号でない場合スペースを前に付ける 0: フィールド幅いっぱいに左側から0を詰める #: 別の出力形式を指定。 o: 先頭の桁を0にする x: 0でない結果の先頭を0xにする e,f,g: 出力に必ず小数点を付ける g: 末尾の0を削除しない 参考: [1] pp

28 printf: 最小フィールド幅 変換された引数は少なくともこの幅になる。 必要ならもっと広い幅のフィールドに印字。
教科書 pp.61, 64-66, 98. printf: 最小フィールド幅 変換された引数は少なくともこの幅になる。 必要ならもっと広い幅のフィールドに印字。 変換された引数がフィールド幅よりも短い場合padding(=詰め物)が行われる。 paddingは通常はスペース。フラグに0が指定された場合は0が用いられる。 *: 次の引数の値を用いる 参考: [1] pp

29 printf: .精度 「.」(ピリオド): フィールド幅と精度の分離子(separator) 文字列に対しては印字する最大文字数
教科書 pp.61, 64-66, 98. printf: .精度 「.」(ピリオド): フィールド幅と精度の分離子(separator) 文字列に対しては印字する最大文字数 e,fの対しては小数点以下に印字すべき桁数 gに対しては有効数字の桁数 整数に対しては印字すべき最小桁数(頭に0が付加される) *: 次の引数の値を用いる 参考: [1] pp

30 printf: 長さ修飾子 h: short または float として扱う l: long として扱う
教科書 pp.61, 64-66, 98. printf: 長さ修飾子 h: short または float として扱う l: long として扱う L: long double として扱う 参考: [1] pp

31 printf: 変換文字 教科書 pp.61, 64-66, 98. 文字 変換後の引数の型 d, i int; 符号付き10進数 o
x, X int; 符号なし16進数 u int; 符号なし10進数 c int; unsigned char に変換された後の単一文字 s char *; 文字列を文字列終端('\0')または指定された桁まで f double; [-]mmm.dddddd 形の10進数。dの桁数は精度で指定 e, E double; [-]m.dddddde±xx型の10進数。dの桁数は精度で指定 g, G double; 指数が-4より小さいか精度以上の場合%e、それ以外は%f扱い p void *; ポインタとして印字(処理系依存) n int *; このprintfでここまでに書き出された文字数を引数に書き込む % %を印字 参考: [1] pp

32 教科書 pp.61, 64-66, 98. printf の詳細 ここでは概略しか示せていないのと一部不正確な部分もあるので、詳細は bash から man コマンドを用いて以下の方法で確認すること 邦訳は以下のページ man sprintf

33 sprintf のマニュアル導入 以下のコマンドを mintty+bash から実行 学内の場合はまず以下の PROXY 設定が必要
教科書 pp.61, 64-66, 98. sprintf のマニュアル導入 以下のコマンドを mintty+bash から実行 学内の場合はまず以下の PROXY 設定が必要 export http_proxy= cygwin-doc パッケージのインストール apt-cyg install cygwin-doc

34 値の読み込み

35 値の読み込み scanf関数を使う scanftest.c キーボードから入力した値を 変数に保存して利用出来る
教科書 pp.80-83, 254. 値の読み込み scanf関数を使う scanftest.c int i; double d; char s[16]; printf("i = "); scanf("%d", &i); printf("d = "); scanf("%lf", &d); printf("s = "); scanf("%s", &s); printf("i = %d\n", i); printf("d = %f\n", d); printf("s = %s\n", s); キーボードから入力した値を 変数に保存して利用出来る $ gcc -g scanftest.c && ./a i = 1234 d = 1234e-5 s = hello, world d = s = hello,

36 scanf 関数 引数: 戻り値: FORMAT: 書式 ...: 任意の数の引数 値を格納する変数へのポインタ
教科書 pp.80-83, 254. scanf 関数 int scanf(const char *FORMAT, ...); 引数: FORMAT: 書式 ...: 任意の数の引数 値を格納する変数へのポインタ 戻り値: 変換され代入された入力項目の数。 ファイル終端またはエラーの場合EOF。 参考: [1] pp

37 scanf: 書式 スペース、タブ: 無視される (%でない)普通の文字: 入力の次の空白でない文字とマッチ 変換仕様: int a;
教科書 pp.80-83, 254. scanf: 書式 スペース、タブ: 無視される (%でない)普通の文字: 入力の次の空白でない文字とマッチ 変換仕様: %[*][最大フィールド幅][ターゲット幅]変換文字 &: アドレス演算子 変数へのポインタを得る int a; scanf("%d", &a); スカラ変数の前には & を付ける 配列変数、ポインタ変数には不要 入力文字列を10進数として扱い int型の整数型変数へ代入 参考: [1] pp.250,

38 scanf: 変換仕様 *: 入力フィールドはスキップされる 代入抑止 最大フィールド幅: 読み込む最大文字数 ターゲット幅:
教科書 pp.80-83, 254. scanf: 変換仕様 *: 入力フィールドはスキップされる 代入抑止 最大フィールド幅: 読み込む最大文字数 ターゲット幅: h: int を short に l: int を long に、float を double に L: float を long doubleに 参考: [1] pp

39 scanf: 変換文字 教科書 pp.80-83, 254. 文字 入力データ; 引数の型 d 10進数; int * i
整数; int * (頭に0,0xが付くと8,16進数とみなす) o 8進数; int * u 符号なし10進数; unsigned int * x 16進数; int * c 文字; char * (末尾に'\0'を付加しない) s 非空白文字の文字列; char * (末尾に'\0'を付加) e,f,g 浮動小数点数; float * p printf("%p") で印字されるポインタ値; void * n これまでに読み込まれた文字数; int * [...] [...]+; char * (末尾に'\0'を付加) [^...] [^...]+; char * (末尾に'\0'を付加) % %; 参考: [1] pp

40 教科書 pp.80-83, 254. scanfの詳細 ここでは概略しか示せていないのと一部不正確な部分もあるので、詳細は bash から man コマンドを用いて以下の方法で確認すること 邦訳は以下のページ man sscanf

41 scanf の引数とポインタ 値の代入するには変数のアドレスが必要 int a; scanf("%d", &a);
教科書 pp.80-83, 254. scanf の引数とポインタ 値の代入するには変数のアドレスが必要 : int a; scanf("%d", &a); &a 0x?? 0x~00 0x?? 0x~01 32bit 0x?? 0x~02 scanf に値の格納先の アドレスを渡す 0x?? 0x~03 0x?? 0x~04 &: アドレス演算子 変数が配置されているメモリ上のアドレスが得られる このアドレスのことをC言語ではポインタと呼ぶ 0x?? 0x~05 0x?? 0x~06 a 0x???????? 0x?? 0x~07 0x?? 0x~08 :

42 scanf: C99 の stdint.h の場合 #include<inttypes.h> して SCN~ を使う
補足 scanf: C99 の stdint.h の場合 #include<inttypes.h> して SCN~ を使う "%hd" → "%"SCNd16 "%d" → "%"SCNd32 "%u" → "%"SCNu32 使う bit 数を確実に保証出来る 実装依存なので 欲しい桁数が扱えないかも? 参考: [1] pp

43 buffer obverflow の脆弱性 確保した配列よりも長い文字列を入力 他の変数の領域を 侵食してしまう
備考 buffer obverflow の脆弱性 確保した配列よりも長い文字列を入力 $ gcc -g scanftest.c && ./a i = 1234 d = 1234e-5 s = i = d = 他の変数の領域を 侵食してしまう

44 buffer obverflow の脆弱性の仕組み
備考 buffer obverflow の脆弱性の仕組み メモリ上の変数の割り当て 0x?? 0x~00 : char s[16]; 0x?? 0x~0f 0x?? 0x~10 確保したサイズ以上の データを書き込むと 他の変数のデータを 上書きしてしまう。 : double d; 0x?? 0x~17 : 0x?? 0x~1c : int i; 0x?? 0x~1f :

45 buffer obverflow の脆弱性の対策
備考 buffer obverflow の脆弱性の対策 最大フィールド幅を明記する! "%s" → "%15s" 終端文字列'\0'も格納する必要があるため、 最大フィールド幅は 確保したバイト数 -1 以下にする必要がある。 char s[16]; なら最大15文字まで

46 マクロ preprocessor のキーワード置換機能 書式: #define マクロ名 置換内容 定数等に名前を付ける際に使う
area_of_a_circle.c #define PI 3.14 // ... float r; printf("circle radius = "); scanf("%f", &r); printf("Area of a circle = %f\n", PI * r * r);

47 マクロ 先程の EOF とか SCNd32 もマクロ それぞれの環境に 適切な数値や文字列等が設定されている
教科書 p.68. マクロ 先程の EOF とか SCNd32 もマクロ $ grep "#define.EOF" /usr/include/stdio.h #define EOF (-1) $ grep SCNd32 /usr/include/inttypes.h #define SCNd32 "d" それぞれの環境に 適切な数値や文字列等が設定されている

48 マクロ PI に関しては実は math.h で提供されている $ grep M_PI /usr/include/math.h
#define M_PI #define M_TWOPI (M_PI * 2.0) #define M_PI_ #define M_PI_

49 ファイルの包含 preprocessor のファイル取り込み機能 別のファイルに記述されたプログラムやマクロ等を取り込む際に使う 書式:
教科書 pp ファイルの包含 preprocessor のファイル取り込み機能 別のファイルに記述されたプログラムやマクロ等を取り込む際に使う 書式: #include <ファイル名> //システム提供ファイル用 /usr/include 等から探して取り込む #include "ファイル名" //ユーザー作成ファイル用 作業ディレクトリから探して取り込む

50 grep コマンド grep [OPTIONS] PATTERN [FILE ...] 引数 OPTIONS:
備考: UNIX コマンド grep コマンド grep [OPTIONS] PATTERN [FILE ...] 検索文字列を含むファイルを検索する 引数 PATTERN: 正規表現等による検索文字列 FILE: 検索対象のファイルやディレクトリ OPTIONS: -R: ディレクトリ下のすべてのファイルを検索 -n: 行番号を表示 -A NUM: マッチ位置の後NUM行も表示 -B NUM: マッチ位置の前NUM行も表示 -C NUM: マッチ位置の前後NUM行も表示

51 正規表現 c 文字c \c 文字\c . 任意の一文字 [...] []内の任意の一文字 [^...] []内に含まれない任意の一文字
備考: UNIX コマンド 正規表現 c 文字c \c 文字\c . 任意の一文字 [...] []内の任意の一文字 [^...] []内に含まれない任意の一文字 * 直前のパターンが0回以上反復 + 直前のパターンが1回以上反復 ? 直線のパターンが0または1回出現

52 演算子

53 sizeof 演算子 変数やデータ型の割り当てバイト数を求める arraysizetest.c
教科書 p.78, 84, 195. sizeof 演算子 変数やデータ型の割り当てバイト数を求める arraysizetest.c int a[10]; // 要素数10のint型の配列変数 printf("%d\n", sizeof(int)); //int型の割り当てバイト数 printf("%d\n", sizeof(a)); //配列変数aの割り当てバイト数 printf("%d\n", sizeof(a[0]));//変数a[0]の割り当てバイト数 printf("%d\n", sizeof(a)/sizeof(a[0])); //配列変数aの要素数 $ gcc -g arraysizetest.c && ./a 4 40 10

54 型変換(cast)演算子 (変換したい型) 値 cast 演算子 (type) type: 任意のデータ型 casttest.c
int a = 1; int b = 2; double x = a / b; double y = a / (double) b; printf("%f\n", x); printf("%f\n", y); 整数同士の割り算だと 1/2 が 0 になっている。 $ gcc casttest.c && ./a b の値を double 型に 変換

55 算術演算子 教科書 p.69, 84. 算術演算子 演算子の機能 書式 単項演算子 + 被演算数の値 + expr - 被演算数の符号反転
二項演算子 加算 expr1 + expr2 減算 expr1 – expr2 * 乗算 expr1 * expr2 / 除算 expr1 / expr2 % 剰余算 expr1 % expr2

56 代入演算子、複合代入演算子 複合代入演算子はvar=var+exprのような演算と代入を同時に行う 教科書 pp.75-79, 84.
演算子の機能 書式 = 代入 var = expr 複合代入演算子 += 加算 var += expr -= 減算 var –= expr *= 乗算 var *= expr /= 除算 var /= expr %= 剰余算 var %= expr &= ビット毎のAND var &= expr ^= ビット毎のXOR var ^= expr |= ビット毎のOR var |= expr <<= 左シフト var <<= expr >>= 右シフト var >>= expr 複合代入演算子はvar=var+exprのような演算と代入を同時に行う

57 bit演算子 教科書 pp.78-79, 84. 算術演算子 演算子の機能 単項演算子 ~ 1の補数 ~ expr 二項演算子
<< 左シフト expr1 << expr2 >> 右シフト expr1 >> expr2 & ビット毎のAND expr1 & expr2 ^ ビット毎のXOR expr1 ^ expr2 | ビット毎のOR expr1 | expr2

58 bitシフト(論理シフト) (符号なし整数の場合)
教科書 pp.78-79, 84. bitシフト(論理シフト) (符号なし整数の場合) 利用可能 bit の外側には 0が充填される 論理シフトであれば 左シフト、右シフト共に 符号付き、符号なしで結果は共通 0xe8 1 << 2 0x90 0xe8 1 >> 2 0x3a

59 bitシフト(算術シフト) (符号付き整数の場合?)
教科書 pp.78-79, 84. bitシフト(算術シフト) (符号付き整数の場合?) 最上位ビットより上位は符号拡張される 符号ビットが0なら0、1なら1が充填される 左シフトは 符号付き、符号なしで結果は共通 右シフトは最上位ビットの値により 符号付き、符号なしで結果が異なる 0x1b 1 >> 2 0x06 0xe8 1 >> 2 環境依存なので、環境によっては 論理シフトになる可能性も 考慮しておくこと。 0xfa

60 右シフト 実際の環境はどうなっているのか? bitshifttest.c
教科書 pp.78-79, 84. 右シフト 実際の環境はどうなっているのか? bitshifttest.c unsigned int uc = 0xe ; // == 0b signed int sc = 0xe ; // == 0b uc >>= * 3; sc >>= * 3; printf("%02x\n", uc & 0xff); // 0b == 0x3a printf("%02x\n", sc & 0xff); // 0b == 0xfa ?

61 右シフト 算術シフトになっている環境が多い? 教科書 pp.78-79, 84. $ gcc bitshifttest.c && ./a
fa 64bit 版 cygwin GNU C 4.8.2 >bcc32 bitshifttest.c && bitshifttest ... 3a fa Borland C++ 5.5 >cl bitshifttest.c && bitshifttest ... 3a fa Visual Studio 2013 Express Desktop Windows 64bit 版

62 論理演算 論理演算子による演算結果は真(=1)または偽(=0)となる 教科書 pp.78-79, 84. X Y X AND Y
X OR Y X XOR Y NOT X 1 論理演算子 ビット毎の論理演算子 意味 英語表記 && & 論理積 AND || | 論理和 OR ^ 排他的論理和 XOR (exclusive or) ! ~ 論理反転 NOT 論理演算子による演算結果は真(=1)または偽(=0)となる

63 C言語の論理値(真偽値) 数値を論理値として用いている 論理演算とビット毎の論理演算に注意 logictest.c
教科書 pp.78-79, 84. C言語の論理値(真偽値) 数値を論理値として用いている 論理演算とビット毎の論理演算に注意 論理値 数値 真偽値判定時 0のみが偽として扱われる 1 0以外はすべて真として扱われる logictest.c int x = 1; // = 0b01 int y = 2; // = 0b10 printf("x && y = %d\n", x && y); printf("x || y = %d\n", x || y); printf("x & y = %d\n", x & y); printf("x | y = %d\n", x | y); $ gcc logictest.c && ./a x && y = 1 x || y = 1 x & y = 0 x | y = 3

64 論理演算とビット毎の論理演算 論理演算を行う単位が違う 1 1 1 1 1 1 1 1 論理演算子 ビット毎の論理演算子 1 1
教科書 pp.78-79, 84. 論理演算とビット毎の論理演算 論理演算を行う単位が違う 1 1 1 1 1 1 1 1 論理演算子 ビット毎の論理演算子 1 1 論理演算では 全体を1つの論理値として扱う ビット毎の論理演算では 各ビットを個別に扱う

65 bit 毎の AND による bit mask bit毎にANDを取った結果が得られる 1 1 1 1 & 1 1 1 1 1
教科書 pp , p.84. bit 毎の AND による bit mask bit毎にANDを取った結果が得られる 1 1 1 1 & 1 1 1 1 X & Y で 右辺の値をマスクとして用いた場合 0: 0でクリア 1: 元の値をそのまま通過 1

66 bit 毎の OR による bit mask bit毎にORを取った結果が得られる 1 1 1 1 | 1 1 1 1 1 1 1 1 1
教科書 pp , p.84. bit 毎の OR による bit mask bit毎にORを取った結果が得られる 1 1 1 1 | 1 1 1 1 1 1 1 1 X | Y で 右辺の値をマスクとして用いた場合 0: 元の値をそのまま通過 1: 1でクリア 1 1 1 1 1

67 bit 毎の XOR による bit 反転 bit毎にXORを取った結果が得られる 1 1 1 1 ^ 1 1 1 1 @ @ @ @ 1
教科書 pp , p.84. bit 毎の XOR による bit 反転 bit毎にXORを取った結果が得られる 1 1 1 1 ^ 1 1 1 1 @ @ @ @ X ^ Y で 右辺の値をマスクとして用いた場合 0: 元の値をそのまま通過 1: bit を 0⇔1 反転 1 1 同じ値で再度 XOR を取ると元に戻るので 簡易暗号的な使い方も出来る

68 1の補数演算子 要は単なるビット毎の論理反転 ~ 1 1 1 1 ビット毎の論理反転 1 1 1 1
教科書 pp , p.84. 1の補数演算子 要は単なるビット毎の論理反転 ~ 1 1 1 1 ビット毎の論理反転 1 1 1 1

69 補数とは 基数𝑏(𝑏進数) 𝑛桁で表現可能な整数𝑎に対し 例: 2進数8桁で表す1について 𝑏 𝑛 −𝑎 : 基数(𝑏)の補数
𝑏 𝑛 −𝑎 : 基数(𝑏)の補数 𝑏 𝑛 −𝑎−1 : 減基数(𝑏−1)の補数 例: 2進数8桁で表す1について 2の補数 0b – 0b = 0b 1の補数(単なるビット毎の論理反転) 0b – 0b = 0b 訂正: 誤: 0c 正: 0b

70 インクレメント、デクレメントの演算子 int i = 5; printf("%d\n", ++i);
教科書 pp , p.84. インクレメント、デクレメントの演算子 算術演算子 演算子の機能 前置演算子 ++ インクレメント ++expr -- デクレメント --expr 後置演算子 expr++ expr-- 前置演算子は演算後に値を取り出す。 後置演算子は演算前に値を取り出す。 int i = 5; printf("%d\n", ++i); printf("%d\n", --i); printf("%d\n", i++); printf("%d\n", i--); $ gcc incrtest.c && ./a 6 5

71 比較演算子 (関係演算子、等値演算子) 演算結果は真(=1)または偽(=0)となる 教科書 pp.117-118, 147. 演算子
比較の意味 関係演算子 < 左辺が小 expr1 < expr2 <= 左辺が小または等しい expr1 <= expr2 > 左辺が大 expr1 > expr2 >= 左辺が大または等しい expr1 >= expr2 等値演算子 == 等しい expr1 == expr2 != 等しくない expr1 != expr2 演算結果は真(=1)または偽(=0)となる

72 演算子の優先度 優先度 高 低 [1] p.65. より 演算子 結合規則 備考 ( ) [ ] -> . 左から右→
( ) [ ] -> . 左から右→ ! ~ * & (type) sizeof 右から左← 単項演算子 * / % 二項演算子 + - << >> bitシフト < <= > >= 関係演算子 == != 等値演算子 & bit毎のAND ^ bit毎のXOR | bit毎のOR && 論理演算子(AND) || 論理演算子(OR) ?: 三項演算子 = += -= *= /= %= &= ^= |= <<= >>= 代入演算子 , [1] p.65. より

73 配列変数

74 配列変数 同じ変数名で複数の要素を管理する char a[10]; // 要素数10のchar型変数の宣言 教科書 pp.85-108.
初期値式が与えられなかった場合、値は不定 a[0] ? a[1] ? a[2] ? a[3] ? a[9] ? ... 要素数10の添え字付き変数 [1] pp , p.273.

75 配列変数 配列変数の要素への代入 char a[10]; // 要素数10のchar型変数の宣言
教科書 pp 配列変数 配列変数の要素への代入 char a[10]; // 要素数10のchar型変数の宣言 a[0] = 'a'; // 0番目の要素へ代入 宣言後の代入 初期値式が与えられなかったので、値は不定 a[0] 'a' a[1] ? a[2] ? a[3] ? a[9] ? ... 要素数10の添え字付き変数 [1] pp , p.273.

76 配列変数 添え字は値が取れれば変数や数式でも良い int i = 1; char a[10]; // 要素数10のchar型変数の宣言
教科書 pp 配列変数 添え字は値が取れれば変数や数式でも良い int i = 1; char a[10]; // 要素数10のchar型変数の宣言 a[i + 1] = 'a'; // 2番目の要素へ代入 a[0] ? a[1] ? a[2] 'a' a[3] ? a[9] ? ... 要素数10の添え字付き変数 [1] pp , p.273.

77 配列変数 確保した領域外はアクセスは禁止 char a[10]; // 要素数10のchar型変数の宣言 short b = 0x1234;
教科書 pp 配列変数 確保した領域外はアクセスは禁止 char a[10]; // 要素数10のchar型変数の宣言 short b = 0x1234; a[10] = 'a';// 宣言された領域外へのアクセス ここに書き込むと何が起こるか分からない b 0x1234 a[0] ? a[1] ? a[2] ? a[3] ? a[9] ? a[10] 'a' ... 他の変数が使っていたらその値を壊してしまう 要素数10の添え字付き変数 [1] pp , p.273.

78 配列変数 初期値式による配列変数の初期化 char a[10] = {'a', 'b'}; //初期値式付きの
教科書 pp 配列変数 初期値式による配列変数の初期化 char a[10] = {'a', 'b'}; //初期値式付きの //要素数10のchar型変数の宣言 初期値式による初期化 初期値式が要素数より少ない場合、残りは0で初期化 a[0] 'a' a[1] 'b' a[2] a[3] a[9] ... 要素数10の添え字付き変数 [1] pp , p.273.

79 配列変数 初期値式による配列変数の初期化 char a[] = {'a', 'b'}; //初期値式付きで
教科書 pp 配列変数 初期値式による配列変数の初期化 char a[] = {'a', 'b'}; //初期値式付きで //要素数を省略したchar型変数の宣言 初期値式による初期化 a[0] 'a' a[1] 'b' 初期値式の要素数分確保される [1] pp , p.273.

80 配列変数 文字列による初期化(要素数指定) char a[10] = "ab"; //文字列による初期値付きの
教科書 pp 配列変数 文字列による初期化(要素数指定) char a[10] = "ab"; //文字列による初期値付きの //要素数10のchar型変数の宣言 文字列と文字列終端の'\0' 初期値式が要素数より少ない場合、残りは0で初期化 a[0] 'a' a[1] 'b' a[2] a[3] a[9] ... 要素数10の添え字付き変数 [1] pp , p.273.

81 配列変数 文字列による初期化(要素数自動決定) char a[] = "ab";//文字列による初期値付きで
教科書 pp 配列変数 文字列による初期化(要素数自動決定) char a[] = "ab";//文字列による初期値付きで //要素数を省略したchar型変数の宣言 文字列と文字列終端の'\0' a[0] 'a' a[1] 'b' a[2] 文字列の文字数+文字列終端'\0'の1文字分の要素 [1] pp , p.273.

82 変数の初期化 明示的な初期化がない場合 初期化する場合 外的変数、静的変数→0 自動変数、レジスタ変数→不定
外的変数、静的変数←定数式でのみ初期化可 コンパイル時に1度だけ初期化される 自動変数、レジスタ変数←任意の式で初期化可 実行時にブロック毎に初期化される [1] pp , p.273.

83 配列変数の初期化 要素数を与えない場合 要素数を与えた場合 初期値式の数で配列のサイズが決まる 初期値式を与えない場合 初期値式を与える場合
値は不定 初期値式を与える場合 要素数を超えるとエラー 要素数に足りない部分は0で初期化される [1] pp , p.273.

84 制御構造

85 条件分岐 (if 文) 真偽値による場合分け if (条件式) { // 条件式が真の場合の処理1 } 教科書 pp.130-133.

86 条件分岐 (if, else 文) 真偽値による場合分け if (条件式) { // 条件式が真の場合の処理1 } else {
教科書 pp 条件分岐 (if, else 文) 真偽値による場合分け 条件式 if (条件式) { // 条件式が真の場合の処理1 } else { // 条件式が偽の場合の処理2 } 処理1 処理2

87 入れ子の条件分岐 (if, else 文) 真偽値による場合分け if (条件式1) { // 条件式1が真の場合の処理1 } else {
教科書 pp 入れ子の条件分岐 (if, else 文) 真偽値による場合分け 条件式1 if (条件式1) { // 条件式1が真の場合の処理1 } else { if (条件式2) { // 条件式1が偽かつ // 条件式2が真の場合の処理2 // 条件式2が偽の場合の処理3 } 処理1 条件式2 処理2 処理3 if は任意の数入れ子に出来ます。

88 条件分岐 (if, else if, else 文) 真偽値による場合分け if (条件式1) { // 条件式1が真の場合の処理1
教科書 pp 条件分岐 (if, else if, else 文) 真偽値による場合分け 条件式1 if (条件式1) { // 条件式1が真の場合の処理1 } else if (条件式2) { // 条件式1が偽かつ // 条件式2が真の場合の処理2 } else { // 条件式2が偽の場合の処理3 } 処理1 条件式2 処理2 処理3 else if は任意の数追加出来ます。

89 多分岐判断機構 (switch 文) 値による場合分け switch (式) { case 値1: // 式が値1の場合の処理1
教科書 pp 多分岐判断機構 (switch 文) 値による場合分け switch (式) { case 値1: // 式が値1の場合の処理1 case 値2: // 式が値2の場合の処理2 default: // 他の条件に // 当てはまらない場合の処理N }; 値1 break 処理1 値2 break 処理2 default break 処理N break 文を入れておかないと 次の条件の処理を 連続して実行するので注意。

90 前判定ループ (while 文) 真偽値による繰り返し while (条件式) { // 条件式が真の場合の処理 }
教科書 pp 前判定ループ (while 文) 真偽値による繰り返し 条件式 while (条件式) { // 条件式が真の場合の処理 } 処理

91 後判定ループ (do while 文) 真偽値による繰り返し do { // 条件式 が真の場合の処理 } while (条件式);
教科書 p.123. 後判定ループ (do while 文) 真偽値による繰り返し 処理 do { // 条件式 が真の場合の処理 } while (条件式); 条件式 do while 文は、ループ内の処理を 最低1回は実行する。

92 初期化・更新処理付きループ (for 文) 真偽値による繰り返し for(式1; 式2; 式3) { // 式2が真の場合の処理 };
教科書 pp 初期化・更新処理付きループ (for 文) 真偽値による繰り返し 式1 for(式1; 式2; 式3) { // 式2が真の場合の処理 }; 式2 処理 前判定ループだが 式1による初期化と 式3による更新処理を ひとまとめにして書ける。 式3

93 参考文献 [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準拠、共立出版(1989)


Download ppt "プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)"

Similar presentations


Ads by Google