This project has been created as part of the 42 curriculum by syokota.
C99標準規格のlibc内で定義されている、printf関数の cspdiuxX%のフラグに対応した ft_printf関数を自作するプロジェクトです。
ここで作成された静的ライブラリ(libftprintf.a)は、別のC言語のプロジェクトにおいて利用可能です。
すべての関数ファイル (*.c) は、cc -Wall -Wextra -Werror のフラグでコンパイルされます。
makeまたはmake all: 関数をコンパイルし、libftprintf.aを作成します。make clean: コンパイル時に生成されたオブジェクトファイル (*.o) を削除します。make fclean: オブジェクトファイル (*.o) と libftprintf.a を削除します。make re: ライブラリを再コンパイルします。
このライブラリを別のプロジェクトで使用する際には、以下の手順で使用できます。
新しいプロジェクトのディレクトリ内に、libftprintfのフォルダ (printf.h, libftprintf.a)を配置します。
.cファイルの先頭で、ヘッダーを読み込みます。
#include "libftprintf/printf.h" // パスは配置場所に合わせて調整
コンパイラにlibftの場所を指定する必要があります。
-I: ヘッダファイルがある場所を指定-L: ライブラリファイル (.a) がある場所を指定-l: ライブラリ名を指定 (libft.aの場合、ftprintfと記述)
cc main.c -I./libftprintf -L./libftprintf -lftprintf
プロトタイプは、以下のとおりです。
int ft_printf(const char *, ...);
標準出力ストリームstdoutに出力を書き込みます。また、stdargの可変長引数機能を介してアクセスされる引数が、出力用にどのように変換されるかを指定するフォーマット文字列の制御下で、出力を書き込みます。フォーマット文字列は、初期シフト状態(存在する場合)で始まり、初期シフト状態で終わる文字列です。 フォーマット文字列は、0 個以上のディレクティブで構成されます。 通常の文字(%以外)は、出力ストリームにそのままコピーされます。 本関数に導入されている変換指定子は以下の通りです。
%c: int 型の引数をchar 型に変換し,変換結果の文字を書き込む%s: 文字配列の先頭要素へのポインタを文字列に変換する%p: void *型のポインタ引数を16進数形式に変換する%d: int 型の引数を 10 進符号付き整数に変換する%i: int 型の引数を 10 進符号付き整数に変換する%u: unsigned int 型の引数を 10 進符号無し整数に変換する%x: unsigned int 型の引数を 16 進符号無し整数に変換する%X: unsigned int 型の引数を 16 進符号無し整数に変換する%%:%を出力する
正常に終了した場合、本関数は出力されたバイト数(文字列への出力終了に使用されるヌルバイトを除く)を返します。
標準のprintfは、途中で標準出力(ストリーム)が閉じられたりエラーが発生したりした場合、これまで出力した文字数に関わらず即座に負の値を返します。この仕様を忠実に再現するため、本関数では、システムコールであるwrite関数の戻り値を末端の関数ft_printf_char などで必ず受け取り、-1(書き込み失敗)であった場合は即座に処理を中断し、親関数、さらにその親関数へと -1を返し続ける設計にしています。
オーバーフローによる未定義動作の回避のために、整数やメモリアドレスの計算において、以下の型変換(キャスト)を意図的に行う設計にしています。
- 符号付き整数(%d, %i)の処理では、
int型の引数を一度long型に格納してから絶対値の計算を行う。 - ポインタ(%p)の処理では、
void *型のアドレスを一度uintptr_t型 にキャストしてから16進数の計算に渡す。
文字列を複数回走査したり、事前にフォーマット指定子の数を数えたりする無駄な処理を省き、時間計算量 O(N) で最速で出力とカウントを完了させるため、フォーマット文字列(format)を読み進める際、文字列の先頭から末尾\0までを1回の while ループで1文字ずつ解析します。%を検知した場合は次の文字を先読みし、分岐処理を行う設計にしています。
- man page(glibc) : 標準関数の仕様や挙動の主要なリファレンスとして使用。
(https://man7.org/linux/man-pages/man3/printf.3.html) - Qiitaブログ「2016年、C言語はどう書くべきか」をちょっと分析してみる (types編)
(https://qiita.com/hidenorly/items/6a5f234ada98aa538c47) - Qiitaブログ : C言語 printfのフォーマット指定子
(https://qiita.com/keitean/items/7cd52af571d27a1173d0) - 出力フォーマット指定子一覧
(https://www.k-cube.co.jp/wakaba/server/format.html) - Microsoft Build 2026
(https://learn.microsoft.com/ja-jp/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l?view=msvc-170)
- va_list型の概念的な理解
- stdint.hの内容と、uintptr_t型の概念的な理解
- 複雑なエラーメッセージの解読と原因特定
- write関数がエラーを出力したときの適切なハンドリング方法について