[C言語] ライブラリの関数などメモ


よく忘れるのでメモ。随時アップデート中。

-------------------------------------------

## I/O編

### open

```c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
```

`open()`は指定したパスのファイルをオープンし、そのファイルディスクリプタを返します。

#### 戻り値

オープンに成功した場合はそのファイルディスクリプタを返し、エラーが発生した場合は`-1`を返します。
その場合、`errno`に適切な値が設定されます。

-------------------------------------------

### close

```c
#include <unistd.h>

int close(int fd);
```

#### 戻り値

成功した場合は`0`を、エラーの場合は`-1`を返します。
エラーの場合は`errno`に適切な値が設定されます。

-------------------------------------------

### creat


```c
#include ...

int creat(const char* pathname, mode_t mode);
```

### write

ファイル（ソケット）へのデータ書き込み

```c
#include <unistd.h>

int write(int handle, void *buf, unsigned n);
```

| パラメータ | 説明 |
|:------|:-----------------------|
| int handle | ファイルハンドル |
| void *buf | データアドレス（ポインタ） |
| unsigned n | データの大きさ |

戻り値は書き込みに成功した場合は書き込んだバイト数を、失敗した時は`-1`を返します。

-------------------------------------------

### read

ファイル（ソケット）からのデータ読み込み

```c
#include <unistd.h>

int read(int handle, void *buf, unsigned n);
```

| パラメータ | 説明 |
|:------|:-----------------------|
| int handle | ファイルハンドル |
| void *buf | データを格納するアドレス（ポインタ） |
| unsigned n | データの大きさ |

戻り値は読み込みに成功した場合は読み込んだバイト数を、失敗した時は`-1`を返します。

-------------------------------------------

### sscanf

```c
#include <stdio.h>

int sscanf(const char *str, const char *format, ...);
```

`str`から、書式（`format`にしたがって`scanf`関数と同様の変換を続く変数のアドレスに格納する。

#### example

```c
char *text = "Name: edo Age: 20";
char output1[256];
int  output2;
char *format = "Name: %s Age: %d";

sscanf(text, format, output1, &output2);

printf("名前: %s、歳: %d\n", output1, output2); // => "名前: edo、歳: 20"
```

-------------------------------------------

### sprintf

書式`format`にしたがって、`printf()`関数と同様の変換を行った出力を、変数`str`に格納します。

```c
#include <stdio.h>

int sprintf(char *str, const char *format, ...);
```

#### 戻り値

成功時：`str`に格納した文字数（最後の`\0'は除く）
失敗時：EOF

-------------------------------------------

### select

`select()`システムコールは同期的多重I/Oの仕組みを提供します。

```c
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);
```

`select()`システムコールは渡されたファイルディスクリプタセットのいずれかがI/O可能になるまで、または指定された時間が経過するまで内部でブロックすします。

タイムアウトに利用される`timeval`構造体の宣言は以下のようになっています。

```c
#include <sys/time.h>

struct timeval {
	long tv_sec;  // seconds
	long tv_usec; // microseconds
};
```

`select()`に渡すファイルディスクリプタの種類は3種類あり、`readfds`には読み取り用の、`writefds`には書き込み用の、そして`exceptfds`には例外または帯域外データ（緊急データ、急送データ（out-of-band data））それぞれのイベント発生を待ちます。

渡したファイルディスクリプタのどれかがI/O可能になると、I/O可能になったファイルディスクリプタだけを残すように、渡されたファイルディスクリプタセットを変更します。
つまり、残されたファイルディスクリプタを調べればどのファイルディスクリプタがI/O可能になったかが分かる、というわけです。

ちなみに、最初の引数の`n`には、渡すファイルディスクリプタの最大値+1の値を渡します。
（内部的にはその値までの間のファイルディスクリプタを捜査するということ？）


#### ファイルディスクリプタの操作

`select()`システムコールに渡すファイルディスクリプタセットは直接には操作しません。
操作用のヘルパーマクロが用意されているのでそれを利用します。

```c
fd_set writefds;

// ファイルディスクリプタセットからすべてのファイルディスクリプタを削除します。
FD_ZERO(&writefds);

// 第一引数のファイルディスクリプタをセットに追加します。
FD_SET(fd, &writefds);

// 第一引数のファイルディスクリプタをセットから削除します。
FD_CLR(fd, &writefds);

// 第一引数のファイルディスクリプタがセット内にあるかを調べます。
// セットされている場合は非0を、されていない場合は0を返します。
FD_ISSET(fd, &writefds);
```

-------------------------------------------

### mmap

`mmap()`システムコールは、ファイルディスクリプタ`fd`に対応するファイルをメモリにマッピングします。
`offset`バイト目から`len`バイト数分の領域をマッピングします。

これをする大きな利点は、ユーザー空間とカーネル空間でのバッファのコピーなどのオーバーヘッドを省略し、メモリアクセスと同じ方法でファイルへ読み書きできるようになる点です。

```c
#include <sys/mman.h>

void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
```


-------------------------------------------

### munmap

`munmap()`システムコールは、`mmap()`システムコールでマッピングしたメモリ領域を解放します。

```c
#include <sys/mman.h>

int munmap(void *addr, size_t len);
```

`munmap()`システムコールは、プロセスアドレス空間の`addr`から`len`バイト数分のページを削除します。


-------------------------------------------

### stat

`stat()`システムコールはファイルのメタ情報を取得します。

```c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
```

`stat()`は普通のファイルのパスを、`fstat()`はファイルディスクリプタを渡します。
`*buf`には指定したファイルのメタ情報が格納されます。

`lstat()`はシンボリックリンクの場合に動作が異なり、参照先のファイルではなくシンボリックリンク自身の情報を返します。

3つのシステムコールはどれも、処理が成功すると`0`を返し、ファイルのメタ情報をstat構造体に格納します。
エラーが発生した場合は`-1`を返します。

#### stat構造体

stat構造体は以下のように宣言されています。

```c
#include <sys/stat.h>

struct stat {
	dev_t st_dev;
	ino_t st_ino;
	mode_t st_mode;
	nlink_t st_nlink;
	uid_t st_uid;
	gid_t st_gid;
	dev_t st_rdev;
	off_t st_size;
	blksize_t st_blksize;
	blkcnt_t st_blocks;
	time_t 	st_atime;
	time_t st_mtime;
	time_t st_ctime;
};
```

### getenv

ホスト環境が提供する環境リストから、`name`にマッチする文字列を検索します。

```c
#include <stdlib.h>

char *getenv(const char *name);
```

-------------------------------------------

## プロセス編

### system

```c
#include <stdlib.h>

int system(const char *string);
```

`system`関数はコマンドプロセッサへ`string`の文字列を渡し、実行します。

#### sample

`ls`コマンドを実行して`/tmp`ファイル経由で取得する。

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
    char filename[80];
    char str[512];
    char *ptr;
    FILE *fp;

    sprintf(filename, "/tmp/ls%d.tmp", getpid());
    sprintf(str, "ls -1 > %s", filename);
    system(str);

    if ((fp = fopen(filename, "r")) == NULL) {
        fprintf(stderr, "Error!\n");
        return 1;
    }
    while(1) {
        fgets(str, 512, fp);
        if (feof(fp)) {
            break;
        }
        ptr = strchr(str, '\n');
        if (ptr != NULL) {
            *ptr = '\0';
        }
        printf("%s\n", str);
    }
    fclose(fp);

    sprintf(str, "rm -f %s", filename);
    system(str);

    return 0;
}
```

-------------------------------------------

### pipe

`pipe()`はパイプを実行する関数です。

```c
#include <unistd.h>

int pipe(int pipefd[2]);
```

引数には`int`型の配列を渡します。
ここに、パイプの書き込み用と読み込み用のファイルディスクリプタが渡されます。
*（ちなみに添字`0`が読み込み用、添字`1`が書き込み用）*


#### sample

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
    int pipefd[2];
    if (pipe(pipefd) < 0) {
        perror("pipe");
        return 1;
    }

    char *s = "test";
    write(pipefd[1], s, strlen(s));

    char buf[128];
    read(pipefd[0], buf, sizeof(buf));

    printf("buf=[%s]\n", buf);
    close(pipefd[1]);
    close(pipefd[0]);

    return 0;
}
```

-------------------------------------------

### exec

バイナリをメモリにロードし、実行します。

```c
#include <unistd.h>

int execl(const char *path, const char *arg, ...);
```

第一引数に実行するバイナリのパス、第二引数以降は可変引数となり、実行するプログラムに渡す引数となります。
ただし、Unixの規約に従い、プログラムに渡す第一引数（`execl`的には第二引数）は該当プログラムパスの最後の要素を渡します。使用例は以下です。

```c
#include <stdio.h>
#include <unistd.h>

int main(void) {
	int ret;
	
	// 現在起動しているプロセスを`vi`に置き換える。
	ret = execl("/bin/vi", "vi", NULL);
	if (ret == -1) {
		perror("execl");
		return 1;
	}
	
	return 0;
}
```

#### 戻り値

起動エラーの場合は`-1`を返します。
起動成功した場合は関数はリターンしません。


-------------------------------------------


### fork

```c
#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);
```

#### 戻り値

`fork()`の戻り値は、親プロセスは生成した子プロセスのpidとなります。
子プロセス側は`0`が返されます。
生成に失敗した場合は`-1`が返されます。

#### 実行例

さっきの`execl`をベースに、新規プロセスから`vi`を起動してみます。

```c
#include <stdio.h>
#include <unistd.h>

int main(void) {

    pid_t pid;

    pid = fork();
    if (pid == -1) {
        perror("fork");
        return 1;
    }

    if (!pid) {
        int ret;

        ret = execl("/usr/bin/vi", "vi");
        if (ret == -1) {
            perror("execv");
            return 1;
        }
    }

    printf("Success to create a new process.\n");

    return 0;
}
```


-------------------------------------------

### exit

`exit()`関数はライブラリ関数です。（システムコールではありません）
この関数は`atexti()`関数や`on_exit()`関数で登録された関数群を登録したのとは逆順で実行し、プロセスを終了させます。

プロセスを終了するシステムコールは`_exit()`です。

```c
#include <stdlib.h>

void exit(int status);
```

-------------------------------------------

### _exit

`_exit()`システムコールはプロセスを終了させます。
ただ、前述の`exit()`関数を呼び出すべきであり、直接呼んでもあまり意味はありません。

```c
#include <unistd.h>

void _exit(int status);
```

-------------------------------------------

### atexit

```c
#include <stdlib.h>

int atexit(void (*function)(void));
```

`exit()`関数実行時に呼び出される関数を登録します。

登録する関数のプロトタイプは以下です。

```c
void my_function(void);
```

戻り値、引数ともにありません。

-------------------------------------------

### on_exit

SunOS4は、`atexit()`と等価なインターフェースを独自に実装しました。
Linuxでもglibcで実装されています。

```c
#include <stdlib.h>

int on_exit(void (*function)(int, void *), void *arg);
```

動作は`atexit()`と同じですが、登録するプロトタイプが少し異なります。

```c
void my_function(int status, void *arg);
```

`on_exit()`では引数を取ることができます。

-------------------------------------------

### wait

親プロセスが子プロセスの終了を待つケースがあります。
そのときに使うのが`wait()`です。

```c
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
```

`wait()`は終了した子プロセスのプロセスIDを返します。エラーが発生した場合は`-1`です。


#### ゾンビプロセス

子プロセスが先に終了した場合、カーネルは親プロセスがそれを確認できるよう、プロセスを構成するのに最低限必要な情報のみを残した特別な状態に遷移させます。
これを「ゾンビ」と呼びます。

この状態のプロセスは、親プロセスから終了確認されるのを待ち、確認された時点でゾンビ状態から抜け、正式に終了します。


-------------------------------------------

### waitpid

複数の子プロセスを起動し、特定の子プロセスの終了を待ちたい場合があります。
その場合、`wait()`では特定の子プロセスのみを監視するには向きません。
特定の子プロセスの終了を待ちたい場合は`waitpid()`を使います。

```c
#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);
```

引数の`pid`には1つまたは複数のプロセスを特定する条件を渡します。

- `< -1`
	- プロセスグループIDがパラメータの絶対値と一致する子プロセスの終了を待つ。
	- 例えば`-500`を渡した場合はプロセスグループIDが500である任意の子プロセスを意味する。
- `-1`
	- 任意の子プロセスの終了を待つ（つまり`wait()`と同等）
- `0`
	- `waitpid()`を発行したプロセスと同じプロセスグループに属する任意の子プロセスの終了を待つ。
- `> 0`
	- プロセスIDがパラメータに一致する子プロセスの終了を待つ。例えば`500`を渡した場合はプロセスIDが`500`の子プロセスを意味する。


### system

プロセスの起動と終了待ちを行います。

```c
#define _XOPEN_SOURCE
#include <stdlib.h>

int system(const char *command);
```

`system()`システムコールは、プロセスを同期的に起動します。
`system()`はパラメータ`command`に渡されたコマンド（パラメータ文字列も含む）を起動します。
`command`の先頭には`/bin/sh -c`という文字列が自動的に加えられ、文字列はすべてシェルへ渡されます。


-------------------------------------------

## シグナル編

`kill()`システムコールは、killだけではなく任意のシグナルを送信することができる。

```c
#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);
```

`pid`を持つプロセスに、`sig`シグナルを送信します。

なお、シグナルを送るには権限が必要です。
通常は、同一ユーザーのプロセスにのみ、シグナルを送信することができます。
root権限を持つプロセスは任意のプロセスにシグナルの送信が可能です。


### シグナルハンドラ

シグナルが発生した際に、そのシグナルに対してなにがしかの処理をしたい場合があります。
その際に使用されるのがシグナルハンドラです。

シグナルハンドラに設定できる関数のプロトタイプは以下です。

```c
void my_sig_handler(int signo);
```

シグナルハンドラを登録するシステムコールは以下です。

```c
#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signo, sighandler_t handler);
```

なお、`SIGKILL`, `SIGSTOP`は補足できず、登録しても意味がありません。


### シグナルのブロック

シグナルが発生すると、プログラムは現在実行中の場所から、シグナルハンドラの場所へジャンプします。
その際、例えば処理途中でジャンプされてしまうと問題が出る処理があります。
そうした部分を「クリティカルセクション」と呼び、シグナルに割り込まれるのをブロックする仕組みがあります。

```c
#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
```

`sigprocmask()`の動作は`how`によって決定され、以下のいずれかの値を渡します。

- `SIG_SETMASK`  
	カレントプロセスのシグナルマスクを`set`へ変更する。
- `SIG_BLOCK`  
	`set`内にセットされたシグナルをカレントプロセスのシグナルマスクへ追加する。
- `SIG_UNBLOCK`  
	`set`内にセットされたシグナルをカレントプロセスのシグナルマスクから削除する。


-------------------------------------------

## String編

### strcmp

```c
#include <string.h>
int strcmp(const char *s1, const char *s2);
```

文字列`s1`と文字列`s2`を比較する。

【戻り値】

| 戻り値 | 意味 |
|:-------|:-----------|
| 正の値 | s1 > s2 |
| 負の値 | s1 < s2 |
| 0 | s1 == s2 |

※ 大小比較は文字コードによる。

-------------------------------------------

### strchr

```c
#include <string.h>
char *strchr(const char *s, int c);
```

文字列`s`の先頭から文字`c`を探し、最初に見つかった位置をポインタで返す。見つからなかった場合は`NULL`を返す。
*（文字列終了コード`\0`も文字列の一部とみなされる）*

※ 一般的に検索する文字は`int`型にcastする。

#### example

```c
char test[] = "http://css-eblog.com/";
int find = (int)'o';

char *result = strchr(test, find);
printf("%s\n", result); // => "og.com/"
```

-------------------------------------------

### strstr

```c
#include <string.h>
char *strstr(const char *s1, const char *s2);
```

文字列`s1`の先頭から文字列`s2`を検索し、見つかったらその位置のポインタを返す。見つからなかった場合は`NULL`を返す。

#### example

```c
char *s1 = "http://css-eblog.com/";
char *s2 = "css";

char *result = strstr(s1, s2);
printf("%s\n", result); // => "css-eblog.com/"
```


-------------------------------------------

### strcpy

```c
#include <string.h>
char *strcpy(char *s1, const char *s2);
```

文字型配列`s1`に、文字列`s2`を`\0`までコピーする。
`\0`もコピーするため、それを考慮した配列サイズを確保しておく必要がある。
*（s1に、s2の内容をコピーするので引数の順番に注意）*

#### example

```c
char *base = "http://css-eblog.com/";
char result[256];

strcpy(result, base);
printf("%s\n", result); // => "http://css-eblog.com/"
```


-------------------------------------------

### strlen

```c
#include <string.h>
size_t strlen(const char *s);
```

文字列`s`の長さを取得する。長さには`\0`は含まれない。

-------------------------------------------

### memcpy

```c
#include <string.h>
void* memcpy(void *buf1, const void *buf2, size_t n);
```

`n`バイトメモリブロックのコピー

`buf2`の先頭から`n`文字分を、`buf1`へコピーします。
`strcpy()`との違いは`\0`を付加せず、またコピー途中に`\0`があってもコピーを続けます。

-------------------------------------------

## ヘルパー編

### bzero

値0のバイトで埋める

**※ 現在は`memset`を使った方法が推奨されています。`bzero`は廃止予定。**

```c
#include <string.h>
void bzero(void *s, size_t n);
```

-------------------------------------------

### memset

引数`buf`の先頭から`n`バイト分、`ch`をセットします。

```c
#include <string.h>
void* memset(void *buf, int ch, size_t n);
```

※
`ch`を`0`にすることで`bzero`と同じ結果を得ることができます。

```c
memset(&hoge, 0, sizeof(hoge));
```


-------------------------------------------

### atoi

文字列を整数（`int`）に変換します。
*（ASCII to Intの略？）*

```c
#include <stdlib.h>
int atoi(const char *str);
```

#### 余談

ちなみにASCIIは以下の略称のよう。初めて知った・・。

>ASCII（アスキー、英: American standard code for information interchange）は、現代英語や西ヨーロッパ言語で使われるラテン文字を中心とした文字コード。これはコンピュータその他の通信機器において最もよく使われているものである。

[引用 - Wikipedia](http://ja.wikipedia.org/wiki/ASCII)

ちなみに、`int`への変換からピンと来るかもしれませんが、`atol`、`atof`など他の型の数値に変換する関数もあります。

-------------------------------------------

### gethostbyname

ホスト名をIPアドレスに変換します。
[こちらの記事](http://wisdom.sakura.ne.jp/system/winapi/winsock/winSock3.html)から引用させてもらうと、

>DNS との接続や名前の解決は、全て WinSock が担当してくれます
名前の解決は gethostbyname() 関数を使います

なので、これを使うことで適切にIPアドレスに変換してくれるようです。

```c
struct hostent FAR* gethostbyname(const char FAR *name);
```

-------------------------------------------

## ネットワーク編

### socket

TCPまたはUDP通信を行う場合に、OSにソケットの作成を依頼します。

```c
#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);
```

#### domain

プロトコルファミリ。

| ドメインタイプ    | 説明 |
|:--------|:----------------------------------------------|
| AF_INET | インターネット（INET）ドメインの2ホスト間プロセス通信 |
| AF_UNIX | UNIXドメインの1ホスト内プロセス通信。ファイルシステムソケット |
| AF_ISO | IOS標準プロトコル |
| AF_NS | Xerox Network Systemsプロトコル |


#### type

通信の種類を定義。

| タイプ | 説明 |
|:------|:---------------------------------------------------------|
| SOCK_STREAM | 順次双方向バイトストリーム。コネクション型の信頼性が高い通信 |
| SOCK_DGRAM | データグラム。ベストエフォート型の通信 |
| SOCK_ROW | 直接IPを用いた通信 |

#### protocol

End to Endプロトコルを指定。

| プロトコルタイプ | 説明 |
|:------|:---------------------------------------------------------|
| 0 | 自動設定 |
| IPPROTO_TCP | TCP/IP(AF_INET & SOCK_STREAMの場合。0も可） |
| IPPROTO_UDP | UDP/IP(AF_INET & SOCK_DGRAMの場合。0も可） |
| IPPROTO_RAW | ICMP |

### ソケットの破棄

ソケット生成成功時に渡されたソケットディスクリプタの数値を`close`関数に渡します。

```c
int sock = socket(...);

// ------

close(sock);
```

-------------------------------------------

### connect

TCP通信において、クライアントからサーバへコネクションの接続確立要求を行います。

```c
#include <sys/socket.h>
int connect(int socket, const struct sockaddr *address, size_t address_len);
```

- `socket`  
  socket()で作成したソケットディスクリプタを指定します。
- `address`  
  sockaddrへのポインタを指定します。
- `address_len`  
  アドレス構造体のサイズを指定します。

※ 戻り値は、`0`が成功、`-1`が失敗。


-------------------------------------------

### bind

ソケットに名前をつける。

```c
#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
```

`socket()`システムコールでソケットが生成されたとき、ソケットは名前空間（アドレスファミリー）に存在するが、まだアドレスは割り当てられていません。
`bind()`はファイルディスクリプタ（`sockfd`）で参照させるソケットに`addr`で指定されたアドレスを割り当てます。

#### 戻り値

成功した場合は`0`を、失敗した場合には`-1`が返されます。


-------------------------------------------

### listen

コネクションの確立時にクライアント側からの接続要求を待つため、サーバ側で使う。
保留中の要求を格納するキューをサーバで作り、接続を待つ。

```c
#include <sys/socket.h>

int listen(int socket, int backlog);
```

- socket ... ソケットディスクリプタ
- backlog ... キューの長さ設定。5が一般的らしい。

#### 戻り値

成功した場合は`0`が、失敗した場合は`-1`が返されます。

-------------------------------------------

### accept

ソケットへの接続を受ける

```c
#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
```

[こちらを参考](http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/accept.2.html)にさせてもらいました。

>accept() システムコールは、接続指向のソケット型 (SOCK_STREAM, SOCK_SEQPACKET) で用いられる。 この関数は、接続待ちソケット socket 宛ての保留状態の接続要求が入っているキューから 先頭の接続要求を取り出し、接続済みソケットを新規に生成し、 そのソケットを参照する新しいファイルディスクリプターを返す。 新規に生成されたソケットは、接続待ち (listen) 状態ではない。 もともとのソケット sockfd はこの呼び出しによって影響を受けない。
>
引き数 sockfd は、 socket(2) によって生成され、 bind(2) によってローカルアドレスにバインドされ、 listen(2) を経て接続を待っているソケットである。


#### 引数

`addr`引数は`sockaddr`構造体のポインタを渡し、接続相手のソケットのアドレスが格納されます。

`addrlen`引数は入出力両用の引数で、呼び出し時は`addr`が指す構造体のサイズ（バイト単位）が格納されます。


#### 戻り値

成功した場合は新しいソケットディスクリプタを、失敗時は`-1`を返します。