☆ライブラリ関数
◆標準Cライブラリ
standard C library
※libc
/libディレクトリにおかれている
Linuxでは libc.so.6
-(シンボリックリンク)->実ファイル
_◇ライブラリバージョン
※glibcのバージョン確認
ls -l /lib/libc-* | more
libc-2.3.*.soならglibc-2.3
※GNU libcの一次情報はinfoにある
_◇標準入出力ライブラリ
stdio : standard I/O library
カーネルレベルのストリームにAPI層を追加し、使いやすくする。
①バッファリング
システムコールでは大きな塊で読み書きし、stdioでいったんバッファリングすることで効率をあげる
⇒書き込む場合は改行が書き込まれた時点でバッファが一杯にならなくても書き込まれる
⇒stdioがアンバッファモードの場合は即座に書き込まれる
<setvbuf()でセット>
⇒stderrはアンバッファモードである
②FILE型
typedefされた型。カーネルのファイルディスクリプタやstdioのバッファなどの内部情報を格納している
③標準入出力 FILE*型変数
stdin
stdout
stderr
_◇getchar(3), putchar(3)
#include
int getchar(void);
int putchar(int c);
stdin固定のfgetc()相当, stdout固定のfputc()相当
_◇getopt(3)
#include
int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
コマンドライン引数argc, argvを与え、getoptを呼び出す毎に、オプション文字(-を除く)を得ることができる。optstringには受け付けるオプション文字を与える。文字の後の:は、オプションに引数があることを示す。引数へのポインタが変数optargに代入される。オプション文字列の先頭に+を置くと、オプション対象の操作は、非オプション文字列が現れた時点で終了する。デフォルトでは、argvの順序を変更し、オプションを前にもってくる。
指定外のオプションが見つかると標準エラーにエラーを出力し、optoptにオプション文字を保存し、’?’を返す。変数opterrに0を代入することでエラーの出力を抑止できる。
オプションがそれ以上ないと-1を返す。そのときoptindは、オプションでない最初のargvを示す。
※オプション解析API. ショートオプションだけを認識する
※呼び出す毎に「次のオプション」を返し、オプションがなくなれば-1を返すので、「!= -1」でチェックしながらwhileループを回す。
※関連するグローバル変数
char* optarg 現在処理中のオプションパラメータ
int optind 現在処理中のargvでのインデックス
int optopt 現在処理中のオプション文字
int opterr 真ならエラー時にgetopt()がメッセージ表示をする
※「-」で終了した場合は、optindは「-」を指して終了する
※「–」で終了した場合は、optindは、「–」の次を指して終了する
※GNU libcのgetopt()では、オプションがオプション以外のファイル名などの後に現れても受け付ける。伝統的実装ではオプションは常に先に書かねばならない
例)
#include <unistd.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { int flags, opt; int nsecs, tfnd; nsecs = 0; tfnd = 0; flags = 0; while ((opt = getopt(argc, argv, "nt:")) != -1) { switch (opt) { case 'n': flags = 1; break; case 't': nsecs = atoi(optarg); tfnd = 1; break; default: /* '?' */ fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]); exit(EXIT_FAILURE); } } printf("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind); if (optind >= argc) { fprintf(stderr, "Expected argument after options\n"); exit(EXIT_FAILURE); } printf("name argument = %s\n", argv[optind]); /* Other code omitted */ exit(EXIT_SUCCESS); }
_◇getopt_long(3)
#define _GNU_SOURCE #include <getopt.h> int getopt_long(int argc, char * const argv[], const char *optdecl, const struct option *longoptdecl, int *longindex); struct option { const char *name; int has_arg; int *flags; int val; }; extern char *optarg; extern int optind, opterr, optopt;
※ロングオプションも解析できるAPI
※第3引数まではgetopt()と同じ
※第4引数に struct optionという構造体の配列を使ってロングオプションの仕様を与える。配列の最後はすべてのメンバを0にする
│ name ロングオプション名文字列
│ has_arg no_argument(0)、パラメータをとらない
│ required_argument(1)、パラメータ必要
│ optional_argument(2)、とるかもしれない
│ flag NULL、valメンバの値を返す
│ 非NULL、0を返し、*flagsにvalメンバの値代入
│ val falgsで指定される返却値
⇒例えばflagをNULLにして、valを文字’h’としてロングオプション”help”にひもづけておけば、–helpにたいしてショートオプション-hを返すこともできる
⇒flagの非NULLの使い方としては、flagにポインタを与えておき、直接valの値をポインタの指す変数に代入するという方法がある。
例)
#include <stdio.h> #include <stdlib.h> #define _GNU_SOURCE #include <getopt.h> static void do_head(FILE *f, long nlinse); #define DEFAULT_N_LINES 10 static struct option longopts[] = { {"lines", required_argument, NULL, 'n'}, {"help", no_argument, NULL, 'h'}, {0,0,0,0} }; int main(int argc, char *argv[]) { int opt; long nlines = DEFAULT_N_LINES; while ((opt = getopt_long(argc, argv, "n:", longopts, NULL)) != -1) { switch (opt) { case 'n': nlines = atoi(optarg); break; case 'h': fprintf(stdout, "Usage: %s [-n LINES] [file file...]\n", argv[0]); exit(1); case '?': fprintf(stderr, "Usage: %s [-n LINES] [file file...]\n", argv[0]); exit(1); } } if (optind == argc) { do_head(stdin, nlines); } else { int i; for (i = optind; i < argc; i++) { FILE *f; f = fopen(argv[i], "r"); if (!f) { perror(argv[i]); exit(1); } do_head(f, nlines); fclose(f); } } exit(0); } static void do_head(FILE *f, long nlines) { int c; if (nlines <= 0) return; while ((c = getc(f)) != EOF) { if (putchar(c) < 0) exit(1); if (c == '\n') { nlines--; if (nlines == 0) return; } }
_◇getpid(2)
プロセスIDを得る
_◇gets(3)
バッファオーバーフローを起こすので使用しない
_◇malloc(3)
#include <stdlib.h>
void *malloc(size_t size);
sizeバイトのメモリをヒープに割り当てる
戻り値はvoid型なので、適切なポインタにキャストする
⇒割り当てに失敗するとNULLが返る
⇒メモリは初期化されない
⇒free()で解放する
_◇perror(3)
#include <stdio.h>
void perror(const char *s);
現在のerrnoの値から、エラーメッセージを出力する。
文字列引数はそのまま出力される。(何を出力してもよい)
_◇printf(3), fprintf(3)
#include <stdio.h>
int printf(const char *fmt, …);
int fprintf(FILE *stream, const char *fmt, …);
※単なる文字列出力として*fmtのところで文字列を出力すると中に%が入っていると引数をとろうとするので注意
_◇puts(3)
標準出力への文字列出力。かならず末尾で\nも出力する
#include <stdio.h>
int puts(const char *buf);
_◇realloc(3)
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
malloc()で割り当てたメモリのサイズをsizeバイトに拡張もしくは縮小する
⇒返されるptrは移動する可能性があるが、内容はコピーされる。
⇒割り当てに失敗するとNULLが返る
⇒割り当てに失敗してもfree()で解放する必要がある
⇒よって、realloc()の戻り値をチェックなしに元のポインタに代入してしまうとfree()もできなくなる。
使用例) void *tmp = realloc(ptr, ...); if (!tmp) { /* error */ } ptr = tmp;
_◇scanf(3)
フォーマット付入力
⇒バッファオーバーフローの危険がある
_◇strtol(3)
文字列からlong型への変換
long型の範囲を超える大きな数を与えてもLONG_MAXが返る。
数字の後に数字以外の文字が続く場合、エラーにならず数字部分のみが変換される。
※strtolは成功時にerrnoの値を変更することはない
⇒予めerrnoに0を代入しエラー検出することができる。
※strtolは変換をやめた位置を第二引数にセットする
#include <stdlib.h> #include <stdio.h> #include <limits.h> #include <errno.h> int main(int argc, char *argv[]) { long val; char *end; errno = 0; val = strtol(argv[1], &end, 0); if (errno != 0) { perro("strtol"); exit(1); } if (end[0] != '\0') { fprintf(stderr, "Non-digit character: %c\n", end[0]); exit(1); } printf("%ld\n", val); }
_◇syscall(2)
間接システムコール
_◇system(3)
シェルコマンドを実行する
#include <stdlib.h>
int system(const char *command);
例)
system(“ls foo”);
_◇ungetc(3)
バイト単位でバッファに戻す
⇒連続してungetc()はできない。1バイトだけ
#include <stdio.h>
int ungetc(int c, FILE *stream);
※文字列を読んで行って、「ではない」文字を読んで区切りと認識するような処理で使用する。
◆ライブラリ形式
_◇静的ライブラリ
ライブラリの中のオブジェクトファイル単位にリンク時に実行可能ファイルにコピーされリンクされる。
アーカイブファイル(.a)
複数のオブジェクトファイルを1つのファイルにまとめたもの。
静的ライブラリの作成例)
% cc -c -o foo.o foo.c
% cc -c -o bar.o bar.c
% ar ruv libfoo.a foo.o bar.o
静的ライブラリのリンク例)
libfoo.aがライブラリのディレクトリにインストールされていること。
%cc -o baz baz.o -lfoo
_◇共有ライブラリ
複数のプロセスでメモリを共有して参照する。
共有ライブラリの作成例)
% cc -fPIC -c -o foo.o foo.c
% cc -fPIC -c -o bar.o bar.c
% cc -shared -Wl,-soname,libfoo.so.0 -o libfoo.so foo.o bar.o
※共有ライブラリのリンクは、静的ライブラリと同じ手順だが、処理は異なる。
_◇ELF
Executable and Linking Format
主にGNU/Linuxで使われるバイナリフォーマット
ヘッダ構造は elf.h に記述されている。
※ファイル先頭の4バイトは
7F 45 4C 46
「45 4C 46」=ELF
_◇COFF
Common Object File Format
_◇PE
Portable Executable
Windowsの実行形式
0000番地 MZ(4D 5A)
0080番地 PE(50 45)
◆wrapper
まわりをAPIで覆って機能を追加する層のこと
◆著名なライブラリ、その他の使用記事
_◇Boost C++ Library
http://www.boost.org/
※BoostライブラリをCmakeする場合の練習記事
ソフトな忘却力(5) CMakeLists.txtにリンク・ライブラリ指定、Boost
_◇getopt
コマンドライン引数の処理
※getoptを使った実習記事が以下に。
ソフトな忘却力(1) リモート接続でLinux Cプログラミング getopt
_◇libconfig
ファイルに書き込まれたコンフィギュレーション設定を読み取る
※libconfigを使った実習記事が以下に。
ソフトな忘却力(2) ラズパイ4でCプログラミング、libconfig
☆ABI
Application Binary Interface
オブジェクトファイルやライブラリファイルが問題なくリンクできるように、必要な規約を定めたもの
①変数型のバイト数
②CPUレジスタの役割
③構造体、共用体のデータ構造
④関数への値の渡し方、関数の返却値の取得方法