コンパイル、メモリ、コマンドライン引数、暗号化

2024.04.22

コンパイル

人間が書いたコードはvscodeやコンピュータは理解できない。なのでコンパイルという作業が必要になる。

人間が書いたコード(ソースコード) → バイナリーコード(マシーンコード) 

ソースコードをマシーンコードに変換する際にコンパイルを行うが、コンパイルはコンピュータに4つの異なることを自動的に、同時にしている。

Preprocessing

検索と置換を行っている。

コンパイラがコードを上から下へ左から右へと読んだ時に#includeに気づくこと。そしてハードディスク側にあるこれらのファイル(cs50.hやstdio.h)を見つけてそれらを自動的にコピーペーストしている。

Compiling

preprocessingで前処理されたソースコードをアセンブリ言語に変換している。

ソースコードからアセンブリ言語に変換された後、コンピュータの頭脳であるCPUに送られる。アセンブリ命令と言ったりする。

c言語が生まれる前はアセンブリ言語が使われていた。

Assembling

アセンブリ言語を0と1に変換している。

Linking

0と1に変換されたバイナリーデータを1つのファイルにまとめる。

hello.cを取り込み、cs50、stdio.hを結合する。ライブラリによってはリンクされる順番も重要な場合がある。

c言語のコンパイルにはmakeというコマンドを使う。make自体はコンパイラではない。makeコマンドはc言語のclangと言うプログラムを自動的に実行するもの。

clangはc言語のコンパイラ。ソースコードからマシーンコードに変換するためのプログラム。

clangを使って手動でコンパイルしたプログラムのデフォルトのファイル名をa.outと言う。これをアセンブラ出力という。

コマンドラインに引数をつける事も可能

-oでファイル名の指定が可能。-oはoutputの略。

clang -o output_file source_file.c

-l -> リンクインしてコンパイルする。ライブラリをリンクさせる。

clang -o output_file source_file.c -lcs50

この場合はcs50と言うライブラリをリンクしている。

標準I/Oはコンパイルする必要がない。stdio.hヘッダファイルに含まれる関数などはコンパイルしなくても使用できる。

printf()scanf()など。

逆に他のライブラリはコンパイルする必要がある。たとえC言語に付属(c言語の標準ライブラリ)していても、一般に効率のためデフォルトでは有効ではない事もある。(math.hやstdlib.hなど)。

コンピュータのメモリに必要以上のバイナリをロードしないようにするため。

debug

printf・・・プログラムの中で特定の値やメッセージを出力したりする。

debugger・・・プログラムを実行し、その中で発生する問題やバグを特定し解決するためのツール。

メモリ

bool 1 byte
char 1 byte
double 8 bytes
float 4 bytes
int 4 bytes
long 8 bytes
string ? bytes

コンピュータの内部にはRAM(ランダム アクセス メモリ)と呼ばれるチップがある。実行中のコードやプログラムが開いている間のファイルを一時的に保存したりする。

String

stringは文字列の配列であるため何バイトにもなり得る。他の型は明確に定義されたバイト数を持っている。

stringは文字の配列。文字列を区切りたい場合特別な記号nulを使う。バイナリ形式だと8つの0ビットはnulと呼ばれる。

終端文字は文字列の最後に加えられる。アスキーコードだと\0と書く。終端文字は文字列の終わりを示す。

Array

同じデータ型の複数の値をメモリに格納する。同じ変数に複数の値を格納できるようになった。

#include <stdio.h>

int main() {
    int numbers[5]; // 整数型の配列を宣言

    // 配列に値を代入
    numbers[0] = 10;
    numbers[1] = 20;
    numbers[2] = 30;
    numbers[3] = 40;
    numbers[4] = 50;
}

配列にする目的は同じ変数名を使うのを避け、混乱を防ぐため。スペースの節約とかではない。

c言語では算術式に含まれる値の1つがfloatであれば残りの値も同様にfloatに昇格するものとして扱われる。

#include <stdio.h>

int main() {
int a = 5;
float b = 3.2;
float result;

result = a + b; // int型のaがfloat型に暗黙の型変換される
printf("Result: %f\n", result); // 5 + 3.2 = 8.2

return 0;
}

偽を表す0・・・0で偽を表し、それ以外の値(1とか50とか-1とか)で真を表すと言うのが一般的。ブール式の内部では0を返すとfalseと等価になる。

コマンドライン引数

独自のプログラムではコマンドラインに引数を持たせる事もできる。argcは引数の数をargv[]は文字列の配列を保持する。

#include <cs50.h>
#include <stdio.h>
 
int main(int argc, string argv[])
{
    if (argc == 2)
    {
        printf("hello, %s\n", argv[1]);
    }
    else
    {
        printf("hello, world\n");
    }
}

argc -> 引数の数 -> 単語の総数

argv[] -> 文字列の配列

プログラムのmainの戻り値は終了コード(exit status)と呼ばれる。プログラムに問題が生じた場合はmainから0以外の値を返すことになる。1とか。mainは常にintを取るように設定される。

暗号化

暗号技術は、情報をスクランブルしたり、隠したりする技術。

plaintext -> [cipher] -> ciphertext
平文 ->     暗号 ->  暗号文

暗号は通常2つの引数を受け取る。plaintextとkey。

plaintext, key ->  []  -> ciphertext