3 ポイント 投稿者 GN⁺ 2024-10-16 | 1件のコメント | WhatsAppで共有
  • 新しいC標準に合わせたModern C改訂版が無料ダウンロードとして公開され、C言語の学習・参照資料をC23基準であらためて見直せる
  • 改訂の中心はC23対応であり、ISOの出版手続きと時期に合わせて新標準への移行を支援することに焦点がある
  • 主要コンパイラの新しいリリースはC23機能の大半をすでに実装しており、書籍の変更点が実験的な紹介にとどまらず実際の利用環境と結び付いている
  • _BitInt(N), nullptr, auto, typeof, constexpr など、言語・ライブラリの変化が幅広く反映され、従来のCコードの書き方にも影響を与える
  • 既存プラットフォームですぐ試せるように移行用付録と暫定includeヘッダが追加されたが、ManningのMEAPはまだ進行中である

無料公開資料と標準文書

  • Modern C C23エディションは無料でダウンロードできる
  • 書籍専用ページで関連資料もあわせて探せる
  • 改訂版ではさまざまな説明が見直されているが、核心的な目的は新しいC標準であるC23を反映することにある
  • 公開アクセス可能な文書の中では、新標準の内容にもっとも近い資料はN3220 PDFである
  • 主要コンパイラの新しいリリースは、C23がもたらす新機能の大半をすでに実装している

C23の言語変化と移行支援

  • 整数関連の変化が大きな比重を占める
    • 新しいビット精度型**_BitInt(N)**を追加
    • オーバーフローチェック演算とビット操作のための新しいCライブラリヘッダを追加
    • 現代アーキテクチャにおける128ビット型の可能性を反映
    • enum型の実質的な改善も含む
  • C23のその他の新しい概念も含まれる
    • **nullptr**定数とその基盤型
    • attributesによる構文注釈
    • autotypeof を含む型ジェネリックプログラミングの道具
    • 可変長配列にも適用される {} によるデフォルト初期化
    • あらゆる型の名前付き定数のための constexpr
  • 新しい資料では、複合式、ラムダ、「国際化」、プログラム失敗に対する包括的なアプローチまで扱う
  • 既存プラットフォームでC23をすぐ始められるように付録と暫定includeヘッダが追加された
  • Manningの新エディションMEAPはまだ公開中である

1件のコメント

 
GN⁺ 2024-10-16
Hacker News の意見
  • 私のマシンの格納順序であるリトルエンディアンとは異なり、上位桁の表現が先に来る方式はビッグエンディアンと呼ばれるが、現代のプロセッサでどちらも一般的に使われていると言うには、s390x 以外はほとんど残っていないので、少し誇張に感じる
    そろそろ、みんな大好きなニッチ/廃れたビッグエンディアン・アーキテクチャのコメントが付きそう

    • Arm はバイエンディアンで、ほとんどの携帯電話で生きている
      他の上位コメントにもあるように、「現代的」という言葉は必ずしも人気がある、あるいは広く使われているという意味ではない
    • POWER はバイエンディアン。最近の Linux on POWER はリトルエンディアンで、以前はビッグエンディアンの Linux on POWER が一般的だったが、数年前に各ディストリビューションが移行した。一方、AIX と IBM i はビッグエンディアン
      AIX と IBM i は IBM メインフレームほど活発ではないだろうが、AIX は Solaris や HP/UX よりもまだ生きていると言えるし、かつて数多くあった商用 Unix と比べればなおさらだ。IBM i もかろうじて踏みとどまっているが、HP MPE のようにベンダーサポートが公式に終了した競合のレガシー・ミッドレンジプラットフォームよりは、はるかに生きている
    • MIPS はコンシューマー向けネットワーク機器ではまだかなり生きている
    • 見方によっては、すべてのプロセッサが一般的に使っているとも言える。ネットワークバイトオーダーがビッグエンディアンだから
    • Sparc はビッグエンディアンではないのか?
  • C の最も重要な側面は移植性だ。小さなマイクロコントローラからほぼすべてのコンピューティングプラットフォームまで対応できることが核心だが、新しい C バージョンがそこまで採用されるかは疑問だ
    最先端を使いたいなら、C より C++2x や Rust を選ぶと思う。何か見落としているのだろうか? このいわゆるモダン C がもたらす利点が何なのか気になる

    • C コードを書く利点の一つは、慣用的なコードがどうあるべきか、どの言語サブセットが適切か、といった面倒な議論をしなくて済む点だ
      最先端なら Zig を勧める。現代の C++ や Rust より言語の複雑さがずっと低い。C23 の目立たない良い副作用として、... = {}{0} のような構文を C++ により合わせたことで、C ライブラリのメンテナが C コードを C++ コンパイラでビルドしようとする人たちをサポートする面倒が減る、ということがある
    • 過去に C11、GNU 拡張、そして今や C23 に入った個別機能がそうだったように、結局は採用されるだろう。たとえば二進数表記 0b はマイクロコントローラの世界で広く使われている
      マイクロコントローラのツールチェーンは概して GCC の上に作られているので、機能をタダで得られる。常に遅れがちなプロプライエタリな C コンパイラもあるが、20 年前ほど重要ではない
    • こうした機能は結局、主流へ流れ込んでいくだろう。今 C11 がそうなりつつあるのと同じだ
      組み込みや非常に広いアーキテクチャ集合を対象にしていないなら、今日から C23 を使えない理由もない
    • thread_local 指定子はすでにいくつかのマイクロコントローラプラットフォームで使われているが、C11 以前では完全に違法だった。それでもスレッド環境でのメモリ管理を大きく単純化する
      そのためにわざわざ C++ の世界へ入る理由があるだろうか?
    • LLVM/GCC がサポートするターゲットなら、新しい C バージョンも自動的に得られるのでは? ただし、別のアーキテクチャ向けにベンダーが修正した古い GCC ツールチェーンでは得られないだろう
  • 個人的に guarddeferautoconstexprnullptr のようなものは C をずっと複雑にする。単純さが必要だから C を選ぶのに、複雑さが欲しいなら、たいていは望まなくても C++ を選ぶだろうし、むしろ Go や、サーバなら Elixir を選ぶ
    _BitInt(N) も不格好で、幸い今では bool になった _Bool を思い出す。constexprnullptr は C++ 臭が強すぎる。それでも Modern C は素晴らしい本で、使い続けるつもりの C99 用として大いに役立ってきた

    • NULL の何が問題なのかという疑問は、ISO 標準化の数少ない利点のおかげで、関連文書を読めば答えが出る: https://wg21.link/p2312
      要約すると、NULL 引数を型ジェネリックマクロに渡すと驚くような結果が生じる可能性があり、(1 ? 0 : NULL)(1 ? 1 : NULL) のような条件式の扱いが NULL の定義方法によって変わる。また、ポインタを期待する可変引数関数に NULL を渡すと深刻な結果になり得る。最近の多くのアーキテクチャでは intvoid* のサイズが違うため、NULL が単なる 0 だと、誤ったサイズの引数が関数に渡される
    • 複雑さは線形に増えるわけではないと思う。むしろ、より複雑な道具がプロセスと最終結果を単純にすることは多い
      家を建てるのと似ている。ハンマーとドライバーは非常に単純で、クレーンは極めて複雑だが、家づくりを単純にするのはクレーンだ。ハンマーとドライバーだけで家を建てようとすれば、途方もなく複雑な手順を考案しなければならない
      プログラミング言語も同じだ。C++ でジェネリックコンテナを作るのは些細なことだが、C では非常に難しい。void * と手動キャストである程度まねることはできても、面倒でエラーを起こしやすく、コードはより複雑になる
      std::sortqsort も同じだ。テンプレートと関数オブジェクトの力で、実装はより単純で速くなる。void * を渡して実行時に逆参照する必要がなく、比較を関数定義そのものに入れられる。間接呼び出しもスタック渡しもなく、比較関数のインライン化まで可能だ。言語の複雑さは実装の複雑さを意味しない
    • auto は型ジェネリックマクロを扱うときには主に有用だが、通常のコードでは使わないほうがよい。しばらく C++ の世界で流行した almost always auto のような狂気は避けたい
      残念ながらコンパイラごとに少し違いがある。記憶では、Clang は C++ 風の auto を実装し、GCC は C 風の auto を実装していて、auto ポインタで微妙な違いがあった。その違いが今は修正されたのかは分からない
      _BitInt(N) は普通は直接使わず、必要な幅で typedef して使う。たとえば typedef _BitInt(2) u2; のように使う。_B のような不格好な構文は、アンダースコアに続く大文字の組み合わせが C 標準で予約されているため、言語に小さな機能を追加するときに既存コードと衝突しないようにするため必要だ。_Bool という名前も同じ理由だ。私の知る限り、defer は実際には C23 には入らなかった
  • 以前の定義では、NULL がポインタなのか整数なのかさえ指定していなかった。そのため、Posix の ((void*)0) 要件に従わないプラットフォームでは、ポインタ型でもサイズでもない足元の落とし穴だった
    constexprnullptr が C++ っぽいのは、おそらく C++ から逆輸入されたため。それでも NULL は引き続き使えるが、見た目には nullptr として再定義されたようだ

    • このコードにはバグがあり、一部のアーキテクチャではクラッシュする可能性もある: execlp("echo", "echo", "Hello, world!", NULL);
      このコードにはそのバグがない: execlp("echo", "echo", "Hello, world!", nullptr);
      これでもよい: execlp("echo", "echo", "Hello, world!", (char *)NULL);
  • 良い C の本リストがあるか尋ねようとして、自分で答えを見つけた。ここでは Modern C を中級に分類している
    https://stackoverflow.com/questions/562303/the-definitive-c-...

    • Modern C は気に入っており、各所でも高く評価した。中級という分類には同意する
      K&R の現代的な C の伴読書としては、Ben Klemens の 21st Century C と King の C Programming: A Modern Approach のほうが、より取り組みやすい代替だと思う
    • Christopher Preschern の Fluent C: Principles, Practices and Patterns も読む価値がある
    • このリストは完全ではない。たとえば Effective C が抜けている: https://nostarch.com/effective-c-2nd-edition
      個人的には Modern C より Effective C のほうが好きだ。Modern C は非常に厳密で、専門家には必要かもしれない言語注釈付き仕様書を読んでいるような感じで、私のように軽く C を使う人間には読んでいて退屈だ
  • Metaware の High C 拡張の一部はかなり気に入っている
    https://news.ycombinator.com/item?id=41647843
    https://news.ycombinator.com/item?id=38938402

  • この1年以上、個人プロジェクトの言語インタプリタにモダン C++ を使っているが、C++ の精神的負担とツールの問題のため、C に切り替えようかと考え続けている。Visual Studio の IntelliSense は C++20 モジュールを使うと今でもほとんど動作せず、言語の失敗のせいであまりに多くのものがインターフェースへ押し出され、コンパイル時間もひどいものになる
    その一方で、クラス、メンバー関数、ジェネリックプログラミング、名前空間にあまりにも慣れてしまっていて、もう捕まってしまった気もする

    • 長い間 C++ を使ってきたので、C に移るために デストラクタ を手放すつもりはまったくない
      その用途なら C# を検討してみた? Visual Studio は C# との相性のほうがずっと良い
  • macOS Preview でサイドバーの 目次リンク をクリックしても正しく動作しない

    • zathura PDF リーダーでは目次のいくつかのリンクを試したが、正常に動作した
    • 現在の目次は明らかに壊れている
  • 保守しているライブラリで、C コンパイラがすべて C99 をサポートしていると信じられるようになったのは、ほんの数年前のことだ: https://github.com/eyalroz/printf
    ところが数年たつと案の定、どこかの古代の組み込みツールチェーンのために C89 互換性を求める issue が開かれた。だから C23 は良いのだが、20年後くらいにまた話そうという感じだ

  • 実務上、C がなぜ事実上 C99 で止まっているのか を説明する記事を誰かリンクしてくれないだろうか? 話題にする価値のあるプロジェクトで、C11 以降の機能を活用しているものはほとんどない

    • C99 はまだ新しい。Microsoft は C++ にもあるもの以外の実装を拒み、C を殺そうとしていた。MSVC の C99 実装は16年遅れで、最小限しか実装されなかった。C11 実装も11年遅れだった
      何十年もの間 C は事実上凍結されていたため、ユーザー層も、C が今のままであることを好み、古代のガラクタのようなコンパイラのサポートをいとわない人たちへと自然選択されたように思える。忍耐を失った人や21世紀の言語を望んだ人たちは、C++/Rust/Zig などへ去っていった
    • Microsoft は Visual Studio の C コンパイラで、2015年ごろまで C99 機能をほとんど実装せず、事実上 C99 を妨害していた。そして2019年になってようやく失敗を認め、より最近の C バージョンのサポートを再開した。MSVC の C フロントエンドはいまだに Clang や GCC より安定して遅れている
      2010年ごろには MSVC は依然として非常に重要だったが、最近はほとんどの開発者が Linux に移ったように見える視点からすると奇妙に聞こえる。一方で、C11 機能をどうしても必要とするプロジェクトも多くない。C11 は C99 から VLA を取り上げもしたが、それほど惜しい損失ではなかった。C23 は、C99 以降で多くの C コードベースが実際にアップグレードする価値のある最初のバージョンかもしれない