
2026/05/20 22:05
sp.h:C に高品質で超移植可能な標準ライブラリを与えることで改善されたもの
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
The 提供されたサマリーはキーポイントリストとよく一致しており、変更する必要はありません。
サマリー:
このテキストは、過去 1 ヶ年で開発された高品質かつ極めて portable な C 標準ライブラリ「sp.h1」を紹介しています。これはプログラムingu を近代化する一方で libc への依存を最小限に抑えることを目的としています。その核心の革新点は、複雑でしばしば肥大化した libc の構造に依存するのではなく、約 40 つの主要な syscalls に直接相互作用することにあります。単一のヘッダーファイルに収められた 15,000 行を超えるクリーンな C99 コードを包含し、sp.h1 はゼロ初期化によるメモリ管理、可変なグローバル状態の排除、null ターミネーション付き文字列の拒否(代わりに
sp_str_t を使用し、ポインタと長さを組み合わせる)、およびすべての操作についてエラーを返すことで安全性と予測可能性を実現しています。名前空間構成されたライブラリは @tags によって整理されており、最小限のコアのみを提供し、設定を必要としません。本書は、軽量でドロップイン型モジュールとして設計されており、既存の C プロジェクトへの統合が可能で、構造変更が不要です。これにより特定のニーズを満たすものであり、 Entire OS インターフェースを置換したり、既存の libc インターフェースへの準拠を目指したりするものではありません。
portability は厳格な C99 準拠によって達成され、主要なコンパイラ(GCC、Clang、MSVC、MinGW、TCC)を使用して Linux、Windows、macOS、WebAssembly ホストでネイティブにコンパイルすることが可能であり、libc を含めず、あるいは含むことも可能です(Cosmopolitan など)。一方で、珍しいアーキテクチャや小さすぎる使用ケースの一部に対する肥大化したサポートを避けます。パフォーマンス戦略では、特定の使用ケースが必要とする場合にのみ微調整された最適化を行うことを優先し、未知のハードウェア最適化を追いかけて複雑さを犠牲にすることは拒否し、ゼロコピー I/O API を手元に保持します。
実装ではヒープを非基本型(プログラムが所有するメモリ)として扱い、LLVM などの高度な最適化コンパイラを使用してマシンのコード生成を行い、C の強みであるアーキテクチャへの直接コンパイル、最先端のツール群、オペレーティングシステムおよびライブラリで使用される言語との互換性に合わせています。著者は明確に libc の代わりにはならず、近代インターフェースのための柔軟で portable な代替手段であると述べています。協力については Discord (
#sp チャンネル)、IRC (#sp)、または電子メールを通じて歓迎されており、著者はソフトウェアの fundamentals に関するいくつかの誤解を自認しつつも、ライブラリの移植に協力し、フィードバックを受け入れ、実用的な微調整を継続することに意欲的であると強調しています。本文
sp.h1:高品質で超ポータブルな C 標準ライブラリの開発
概要
過去 1 年間にわたって開発された、C プログラミング言語における新たな基準となる単一ヘッダー形式のライブラリです。
- 名称:
sp.h1 - 規模: ソースコード約 15,000 行(単一ヘッダー形式)
- ライセンス・公開元: GitHub で公開済み
- 特徴:
のラッパーではない。libc- 状況に応じて
を使用するかしないかを選択可能(デフォルトは不使用)。libc - 野球関連の機能拡張ライブラリも多数付属する。
基本原理
システムコールへの直接アクセス
すべての C ライブラリは、利用可能な最低限の基底機能(システムコール)に対して直接記述されるべきです。
- OS とコードの間に蓄積された古い実装(くず屑)をシミュレートしたり生成したりする做法は、有用性も生産性もないと判断されます。
libc
は能動的に有害である
libclibc に依存することは一時的な解決策のように思えますが、長期的には害となります。
- 非同期プログラミングの重要性増大: IO 処理において「高速さ」はレジスタ割り当てではなく、適切なカーネル機能の使用にあるためです。
- 古臭いインターフェース:
型のインターフェース(IO の根本単位が不適切)。FILE*- 部分文字列を「悪質」とみなす設計。
- これらは単なる不便さを超え、有害です。
- 方針:
はこれらの依存関係を断ち切ることに注力しています。sp.h1
ヒープは存在しない(メモリ割り当て)
型定義にはアロケータ機能の基底機能が組み込まれています。
typedef enum { SP_ALLOCATOR_MODE_ALLOC, SP_ALLOCATOR_MODE_FREE, SP_ALLOCATOR_MODE_RESIZE, } sp_mem_alloc_mode_t; SP_TYPEDEF_FN( void*, sp_allocator_fn_t, void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr ); typedef struct sp_allocator_t { sp_allocator_fn_t on_alloc; void* user_data; } sp_mem_t;
- 事実の再認識: プログラムが「無から任意量のメモリを割り当てられる」という能力は幻想です。OS はページ単位でメモリを割り当てます。
を通じて動作するランタイムは、「ページサイズ未満の割当が可能」という幻覚を提供しているに過ぎません。malloc()- メモリは「ランタイム」や「ヒープ」のものではなく、プログラムの所有物です。
- ヒープ割り当てを望むのは自由ですが、これを「非選択型」から**「選択型」**へ転換することが推奨されます。
nullptr
文字列(ヌル終端文字列)は悪魔の業である
nullptrヌル終端文字列 (
\0) を採用することは以下の機能を制限します:
- オーナーシップを持たない部分文字列の返還ができない。
- O(1) の時間複雑度で文字列の長さを知る必要がある場合に不利。
- レクサーやパーサが人間工学に優れたビューを返せない。
- インバリッドな中間値を含まずに安全に文字列を構築できない。
代替案:
sp_str_t(ポインタと長さを持つ文字列)。
- 既存 API との互換性の問題は一時的でしたが、現在は意味がないと見直されています。
- パフォーマンスと人間工学を両立したコード例:
sp_str_t content = sp_zero; sp_io_read_file(mem, path, &content); sp_ht(sp_str_t, u32) counts = sp_zero; sp_str_ht_init(mem, counts); sp_da(sp_str_t) lines = sp_str_split_c8(mem, content, '\n'); sp_da_for(lines, i) { sp_da(sp_str_t) words = sp_str_split_c8(mem, lines[i], ' '); sp_da_for(words, j) { u32* count = sp_str_ht_get(counts, words[j]); if (count) { *count = *count + 1; } else { sp_str_ht_insert(counts, words[j], 1); } } }
このコードはソースバッファからデータを複製することなく動作し、高級言語のような可読性を保ちつつ最大のパフォーマンスを実現します。
ソフトウェアの一部であり、外側ではない
sp.h1 は完全に開示され、ユーザーが読み、書き換える、再調整できるものです。
- コア部分: 約 40 のシステムコールのみを使用(唯一のプラットフォーム固有依存)。
- 配布形式: 設定不要の単一ファイル (
) で完結。header - 構造: 極めて整理されており、
によるタグ付けで検索可能(LLM や人間向け)。@tags - ネームスペース: すべての関数が適切に名前空間化されている。
このアプローチにより、OS の複雑な幻想ではなく、真実であるものを薄いながらも有用なものとして統合し、その上から機能構築を行っています。
極めて高い互換性を保つ
sp.h1 は C99 で記述されており、あらゆるコンパイラと動作します。
- プラットフォーム対応: Linux, Windows, macOS, WASM (ブラウザ内)。
- ツールチェーン: MSVC, MinGW, TCC など。
- 環境適応:
不使用環境、Cosmopolitan OS など、奇妙な環境も対応。libc - サイズと性能: ライブラリが巨大であるからではなく、小さくあるからこそできるすべてを実現しています。
明示的であること
暗黙の動作ではなく、すべての挙動を明示する設計を採用しています:
- エラーは常に返され、呼び出し側で処理される。
- 変更可能なグローバル状態が存在しない。
- メモリ割り当て関数はユーザー定義のアロケータを受け取る。
- メモリはゼロで初期化される。
非目標(ここまでは対応しない)
既存のインターフェースへの準拠
- これは
ではありません。libc - 必要な場合のみ尊重しますが、
使用プログラムへの埋め込みでも無侵入かつ動作保証されます。libc
のような挙動を期待すべきものではありません。libc
不明瞭なアーキテクチャや OS への対応
- 現在の焦点:
,x86_64
。aarch64 - WASM: 重要性が増していますが、ネイティブターゲットに次点です。
- 方針: 非推奨プラットフォームへの対応は行わず、合理的なパッチであればマージを検討しますが、膨らませる予定はありません。
パフォーマンス
- 立ち位置: 「低レベルの計算依存型パフォーマンスにおいて、搾り取る価値以上の果汁はない」。
- 設計の難しさ: 未知のハードウェアと使用ケースに対する最適なパフォーマンスを担保するのは困難であり、コードが複雑化します。
- 推奨: パフォーマンスが極めて重要な場合は、実際の用途とハードウェアに特化したコードを使用すべきです。
除外される最適化:
- SIMD によるハッシュテーブルのリ書き換え。
やインラインによる微細なコンパイラ手動調整。LIKELY
検討されている機能:
- 最適化およびゼロコピー IO のための正しい抽象。
- データコピーを不要とする API の設計。
バグ修正も優先されますが、過度な最適化には反対です(理由は単に「忙しい」ため)。
お別れの言葉:C はシンプルであるために価値がある
システムプログラミングにおいて C よりも良い言語は存在しないでしょうか?答えはいいえです。なぜなら C こそが以下の条件を唯一満たすから:
- 任意のマシンコードに直接コンパイルできる。
- 最先端の最適化コンパイラエコシステムが存在する。
- OS および大部分のライブラリと同じ言語で記述されている。
C の価値は、単なるレガシーの上に構築されているからではなく、**「シンプルであること」**にあります。
- LLVM 等の存在により、技術的には誰でも最先端のコンパイラを持ち得ます。
- 他の言語には型系やツールが存在します。
- しかし、そのようなサポートが魔法のように機能し、最適化されつつネイティブにアクセスできるプラットフォームは C です。
皆さんと一緒に取り組んでいきたい
このライブラリ開発者として皆様と連携することを楽しみにしています。
- 支援内容:
- 非慣用的な環境への移植支援。
- 疑問点に関する徹底した解説。
- フィードバックへの丁寧な対応。
- 私の姿勢:
- システムプログラミングの天才ではありませんが、多くの誤解から学び、多大な努力と楽しみを経て開発されたソフトウェアです。
- 「プログラミングが下手」と評されようとも、耳を傾けてまいります。
連絡先:
- Discord サーバー: お待ちしています。
- IRC チャンネル:
。#sp - メール: ドメインはサイトと同じで、ハンドルネームは私の姓です。