C [ c ]は、1970 年代にデニス・リッチーによって作成された汎用プログラミング言語です。C は、その設計上、プログラマがターゲット命令セットに合わせてカスタマイズされた、一般的なCPUアーキテクチャの機能に比較的直接アクセスできるようになっています。オペレーティングシステム(特にカーネル[ 10 ] )、デバイスドライバ、プロトコルスタックの実装に使用されてきましたが、アプリケーション ソフトウェアでの使用は減少しています[ 11 ] 。C は、スーパーコンピュータからマイクロコントローラ、組み込みシステムまで、さまざまなコンピュータで使用されています。
C は、1972 年と 1973 年の間にベル研究所でリッチーによってBプログラミング言語の後継として開発されました。当初の目的はUnix上で動作するユーティリティを構築することでしたが、後に Unix オペレーティングシステムのカーネルの再実装に適用されるようになりました。[ 12 ] 1980 年代には、C は徐々に人気が高まり、最も広く使用されているプログラミング言語の 1 つとなり、[ 13 ] [ 14 ]事実上すべての最新のコンピュータ アーキテクチャとオペレーティングシステム用の Cコンパイラが利用可能になりました。オリジナルの言語設計者が共著した書籍「The C Programming Language」は、長年にわたり、この言語の事実上の標準として機能しました。 [ 15 ] [ 1 ] C は、1989 年以降、米国規格協会(ANSI)によって標準化され、その後、国際標準化機構(ISO) と国際電気標準会議(IEC) によって共同で標準化されました。
C言語は、構造化プログラミング、レキシカル変数スコープ、再帰をサポートする命令型手続き言語 であり、静的型システムを備えています。メモリへの低レベルアクセスと、機械語命令に効率的にマッピングされる言語構造を、最小限の実行時サポートで提供するようにコンパイルされるように設計されています。低レベルの機能を備えているにもかかわらず、C言語はクロスプラットフォームプログラミングを促進するように設計されています。移植性を念頭に置いて記述された標準準拠のCプログラムは、ソースコードをほとんど変更することなく、さまざまなコンピュータプラットフォームとオペレーティングシステム向けにコンパイルできます。
C言語とその標準ライブラリは、他の言語に見られる一般的な機能の一部を直接提供していませんが、それらをサポートできるだけの柔軟性を備えています。例えば、オブジェクト指向とガベージコレクションは、それぞれ外部ライブラリであるGLib Object SystemとBoehmガベージコレクタによって提供されます。
2000年以降、C言語はTIOBEインデックスで最も人気のある言語、または2番目に人気のある言語としてランク付けされるのが通例となっている。[ 16 ]

C言語は、自由形式のソースコードレイアウトを持つ命令型手続き言語です。文はセミコロンで終了し、中括弧を使ってブロックにまとめられます。実行可能なコードはすべて、トップレベルの文ではなく関数内に記述されます。C言語には比較的少数のキーワードしかなく、ユーザー定義の識別子は、キーワードと区別される記号(シジル)で区別されません。
パラメータは値渡しされます。参照渡しはポインタによって実現されます。関数の戻り値は無視できます。関数は通常、別の関数の中にネストできませんが、一部のトランスレータはこれをサポートしています。C は再帰をサポートしており、関数ポインタを使用して実行時多態性を実現できます。制御フローはif、、、、、などの構造によって提供されます。この言語は、、、、、、、などの算術演算子、ビット演算子、論理演算子を提供しfor、1つのステートメントdoで複数の代入を実行できます。ブロック内で宣言された変数は、そのブロック内、かつその宣言より下でのみアクセスできます。whileswitch++=++&||
データ型は弱く強制され、静的であり、プリミティブ型間では暗黙的な型変換が行われます。ユーザー定義型では、型指定子のエイリアスが可能です。配列は角括弧表記で定義およびアクセスされます(例:)month[11]。ユーザー定義構造体型では、関連するデータ要素を単位として渡したりコピーしたりできますが、各フィールドを比較するカスタムコードがない限り、2つの構造体を比較することはできません。共用体は重複するメンバーをサポートしており、複数のデータ型が同じメモリ位置を共有できます。列挙型は整数値のエイリアスをサポートしています。C には専用の文字列型はありませんが、ヌル終端文字列の構文が提供されており、標準ライブラリで関連する処理が行われます。
この言語は、ポインタによるコンピュータメモリへの低レベルアクセス、戻り値を返す関数形式の手続き型構造、voidおよび標準ライブラリ関数による動的メモリ割り当てをサポートしています。マクロ定義、ソースファイルのインクルード、条件付きコンパイルのためのCプリプロセッサが含まれています。モジュール性は、ファイルを個別に処理し、可視性を属性と属性で制御することでサポートされています。コア言語の機能は最小限に抑えられており、I/O、文字列操作、数学関数などの比較的複雑な機能は標準ライブラリを通じて提供されます。コンパイルされたコードは、基盤となるプラットフォームに対して比較的単純な要件しか持たないため、C言語はオペレーティングシステムや組み込みシステムに適しています。staticextern

K&Rの初版に掲載された「Hello, World!」プログラムの例は、ほとんどのプログラミング教科書で入門プログラムのモデルとなっています。このプログラムは標準出力に「hello, world」と出力します。
元のバージョンは次のとおりです。[ 17 ]
main () { printf ( "hello, world \n " ); }より現代的なバージョンは次のとおりです。[ d ]
#include <stdio.h>int main ( void ) { printf ( "hello, world \n " ); }最初の行はプリプロセッサディレクティブで、 で示されます#include。これにより、プリプロセッサはこのコード行をstdio.hヘッダーファイルのテキストに置き換えます。ヘッダーファイルには、 などの入力関数と出力関数の宣言が含まれていますprintf。 の山括弧は、stdio.hコンパイラに付属のヘッダーファイルを、プロジェクト固有のディレクトリにある同名のファイルよりも優先して選択する検索戦略を使用してヘッダーファイルを見つけることができることを示しています。
次のコード行はエントリポイント関数を宣言しますmain。実行環境はこの関数を呼び出してプログラムの実行を開始します。型指定子は、intこの関数が整数値を返すことを示しています。voidパラメータリストは、この関数が引数を消費しないことを示しています。実行環境は実際には 2 つの引数 (型付きintとchar *[]) を渡しますが、この実装ではそれらを無視します。ISO C 規格 (セクション 5.1.2.2.1) では、void であるか、またはこれらの 2 つの引数のいずれかである構文が要求されます。これは他の関数には適用されない特別な扱いです。
開き括弧は、関数を定義するコードの開始を示します。
次のコード行は、文字列リテラルとして指定されたヌル終端文字列の最初の文字のprintfアドレスを使用して、C標準ライブラリ関数を呼び出します(実行をリダイレクトします) 。このテキストは、改行文字を表すエスケープシーケンスであり、端末に出力されるとカーソルが次の行の先頭に移動します。この関数は値を返しますが、その値は黙って破棄されます。セミコロンは呼び出し文を終了します。\nprintfint;
閉じ括弧はmain関数の終了を示します。C99 より前は、関数return 0;の最後に明示的なステートメントが必要でしたmainが、C99 以降は、main関数は (最初の関数呼び出しであるため)0最後の閉じ括弧に到達すると暗黙的に戻ります。[ e ]
C言語の起源は、 Unixオペレーティングシステムの開発と密接に関係しており、元々はデニス・リッチーとケン・トンプソンが同僚からのアイデアをいくつか取り入れて、 PDP-7上でアセンブリ言語で実装したものです。最終的に、彼らはオペレーティングシステムをPDP-11に移植することにしました。UnixのPDP-11版もアセンブリ言語で開発されました。[ 12 ]
トンプソンは、新しいプラットフォーム用のユーティリティを開発するためのプログラミング言語を求めていました。彼は最初にFortranコンパイラを書こうとしましたが、すぐにその考えを諦め、代わりに最近開発されたシステム プログラミング言語BCPLの簡略版を作成しました。当時 BCPL の公式な説明は入手できなかったため[ 19 ]、トンプソンは構文を「冗長」にならないように変更し、SMALGOL として知られる簡略化されたALGOLに似たものにしました。[ 20 ]彼はその結果をBと呼び[ 12 ]、「多くの SMALGOL 構文を備えた BCPL のセマンティクス」と説明しました。[ 20 ] BCPL と同様に、Bには新しいマシンへの移植を容易にするためのブートストラップコンパイラがありました。 [ 20 ]結局、B は動作が遅く、バイトアドレス指定などの PDP-11 の機能を活用することができなかったため、B で書かれたユーティリティはほとんどありませんでした。
BCPLでは// commentコメントを行末までマークしていたのに対し、Bでは/* comment */PL/1に近いコメント区切り文字を採用し、行の途中にコメントを記述できるようにした。(BCPLのコメントスタイルはC++で再導入されることになる。)[ 12 ]
1971年、リッチーはより強力なPDP-11の機能を活用するためにBの改良に着手した。重要な追加要素は文字データ型であった。彼はこれをNew B(NB)と呼んだ。[ 20 ]トンプソンはUnixカーネルの記述にNBを使用し始め、彼の要求が言語開発の方向性を決定づけた。[ 20 ] [ 21 ]
1972年まで、NB言語にはより豊富な型が追加されました。NBには、intおよびの配列がありchar、これらの型にポインタ、他の型へのポインタを生成する機能、すべての型の配列、および関数から返される型が追加されました。式内の配列は実質的にポインタとして扱われました。新しいコンパイラが作成され、言語はCと改名されました。[ 12 ]
Cコンパイラとそれを使って作られたいくつかのユーティリティは、 Research Unixとしても知られるバージョン2 Unixに含まれていました。[ 22 ]
1973年11月にリリースされたUnixバージョン4では、UnixカーネルはC言語で大幅に再実装されました。[ 12 ]この頃には、C言語は型などの強力な機能を獲得していましたstruct。
プリプロセッサは、アラン・スナイダーの提唱と、BCPL およびPL/Iで利用可能なファイルインクルード機構の有用性を認識して、 1973 年頃に導入されました。その初期バージョンでは、インクルードされたファイルと単純な文字列置換、#includeおよびパラメータなしマクロのみが提供されていました。その後すぐに、主にマイク・レスク、そしてジョン・ライザーによって、引数付きマクロと条件付きコンパイル#defineを組み込むように拡張されました。[ 12 ]
Unix は、アセンブリ言語以外の言語で実装された最初のオペレーティングシステムカーネルの 1 つです。それ以前の例としては、 1961 年のMulticsシステム ( PL/Iで記述) やBurroughs B5000用のMaster Control Program (MCP) ( ALGOLで記述) などがあります。1977 年頃、Ritchie とStephen C. Johnson は、 Unix オペレーティングシステムの移植性を容易にするために言語にさらなる変更を加えました。Johnson のPortable C Compiler は、新しいプラットフォームでの C の実装の基礎となりました。[ 21 ]

1978年、ブライアン・カーニハンとデニス・リッチーは『The C Programming Language』の初版を出版した。[ 23 ]著者の頭文字をとってK&Rとして知られるこの本は、長年にわたり言語の非公式な仕様として機能した。本書で説明されているCのバージョンは、一般的に「K&R C 」と呼ばれている。1978年にリリースされたため、現在ではC78とも呼ばれている。[ 24 ]本書の第2版[ 25 ]では、後述のANSI C規格が扱われている。
K&Rはいくつかの言語機能を導入しました。
long intデータ型unsigned intデータ型=op=-op=-=i=-10i =- 10ii = -10i1989年のANSI規格が発行された後も、多くの古いコンパイラがまだ使用されていたこと、そして丁寧に書かれたK&R Cコードも標準Cとして認められることから、移植性を最大限に高めたい場合、Cプログラマーは長年にわたりK&R Cを「最小公倍数」として利用し続けた。
C言語の後のバージョンでは関数に明示的な型宣言が必要ですが、K&R Cでは、以外の型を返す関数のみint使用前に宣言する必要があります。事前の宣言なしで使用される関数は、を返すものとみなされますint。
例えば:
long long_function ();呼び出し関数(){長いlongvar ;整数変数を登録する;longvar = long_function ();if ( longvar > 1 )intvar = 0 ;それ以外intvar = int_function ();整数変数を返す。}(1行目)の宣言は、long_function()が返されるため必要です。は返さlongれませんint。関数はint_function(11行目)宣言されていなくても、が返されるため呼び出すことができますint。また、変数は、がキーワードのデフォルト型であるため、intvar型として宣言する必要はありません。intregister
関数宣言には引数に関する情報が含まれていなかったため、型チェックは行われませんでしたが、一部のコンパイラは、関数呼び出しごとに引数の数や型が異なる場合に警告を発していました。Unixのlintユーティリティなどのツールが開発され、(とりわけ)複数のソースファイル間での関数使用の一貫性をチェックするようになりました。
K&R Cの出版後、AT&T(特にPCC [ 26 ])や他のベンダーのコンパイラによってサポートされたいくつかの機能が言語に追加されました。これらには以下が含まれます。
言語の人気、標準ライブラリのインターフェースに関する合意の欠如、K&R仕様への準拠の欠如が、標準化の取り組みにつながった。[ 27 ]
1970年代後半から1980年代にかけて、C言語の人気が著しく高まったため、IBM PCをはじめとする様々なメインフレームコンピュータ、ミニコンピュータ、マイクロコンピュータ向けにC言語のバージョンが実装された。
1983年、米国規格協会(ANSI)は、C言語の標準仕様を策定するためにX3J11という委員会を設立しました。X3J11はUnixの実装に基づいてC標準を策定しましたが、Unix Cライブラリの移植性のない部分はIEEEワーキンググループ1003に引き継がれ、1988年のPOSIX標準の基礎となりました。1989年、C標準はANSI X3.159-1989「プログラミング言語C」として承認されました。このバージョンの言語は、ANSI C、Standard C、またはC89と呼ばれることもあります。
1990年、ANSI C規格(書式変更あり)は国際標準化機構(ISO)によってISO/IEC 9899:1990として採用され、これはC90と呼ばれることもあります。したがって、「C89」と「C90」という用語は同じプログラミング言語を指します。
ANSIは、他の各国標準化機関と同様に、C規格を独自に開発するのではなく、ISO/IEC JTC1/SC22 /WG14作業部会が維持管理する国際C規格に準拠するようになった。国際規格の改訂版は、通常、ISOの発行から1年以内に各国で採用される。
C言語の標準化プロセスの目的の一つは、K&R Cのスーパーセットを作成し、その後導入された多くの非公式機能を組み込むことでした。標準化委員会は、関数プロトタイプ(C++から借用)、ポインタ、国際文字セットとロケールvoidのサポート、プリプロセッサの拡張機能など、いくつかの追加機能も盛り込みました。パラメータ宣言の構文はC++で使用されるスタイルを取り入れるように拡張されましたが、既存のソースコードとの互換性を保つため、K&Rインターフェースも引き続き使用が許可されました。
C89は現在のCコンパイラでサポートされており、最新のCコードのほとんどはC89に基づいています。標準Cのみで記述され、ハードウェアに依存する前提条件がないプログラムは、準拠するC実装を備えたプラットフォームであれば、リソース制限内で正しく動作します。このような対策を講じないと、 GUIライブラリなどの非標準ライブラリの使用や、データ型の正確なサイズやバイトエンディアンなどのコンパイラまたはプラットフォーム固有の属性への依存などにより、プログラムは特定のプラットフォームまたは特定のコンパイラでのみコンパイルされる可能性があります。
標準規格に準拠したコンパイラとK&R Cベースのコンパイラのどちらでもコンパイル可能なコードが必要な場合、マクロを__STDC__使用してコードを標準セクションとK&Rセクションに分割し、K&R Cベースのコンパイラで標準Cでのみ利用可能な機能が使用されないようにすることができます。
ANSI/ISO 標準化プロセス後、C 言語の仕様は数年間比較的変化がなかった。1995 年に、1990 年の C 規格に対する規範的修正 1 (ISO/IEC 9899/AMD1:1995、非公式には C95 として知られる) が発行され、いくつかの詳細が修正され、国際文字セットに対するより広範なサポートが追加された。[ 28 ]
C規格は1990年代後半にさらに改訂され、1999年にISO/IEC 9899:1999が発行されました。これは一般に「C99」と呼ばれています。その後、技術訂正により3回修正されています。[ 29 ]
C99では、インライン関数、いくつかの新しいデータ型(複素数を表す型long long intを含む)、可変長配列と柔軟な配列メンバ、 IEEE 754浮動小数点数のサポートの改善、可変引数マクロ(可変引数マクロ)のサポート、BCPLやC++のようにで始まる1行コメントのサポートなど、いくつかの新機能が導入されました。これらの多くは、すでにいくつかのCコンパイラで拡張機能として実装されていました。complex//
C99 は大部分において C90 と後方互換性がありますが、いくつかの点でより厳格です。特に、型指定子のない宣言では暗黙的に が想定されなくなりました。C99のサポートが利用可能であることを示すために、標準マクロが値で定義されています。GCC 、int Solaris __STDC_VERSION__Studio 、およびその他の C コンパイラは、 C99 の多くの新機能またはすべての新機能をサポートしています。ただし、 Microsoft Visual C++の C コンパイラは、C89 標準と、 C++11との互換性のために必要な C99 の部分を実装しています。[ 30 ]199901L
さらに、C99規格では、エスケープ文字(例:または)の形式でUnicodeを使用する識別子のサポートが必須であり、生のUnicode名のサポートも推奨されています。\u0040\U0001f431
C規格の改訂作業は2007年に開始され、2011年12月8日にISO/IEC 9899:2011として正式に発行されるまでは、非公式に「C1X」と呼ばれていた。C規格委員会は、既存の実装でテストされていない新機能の採用を制限するためのガイドラインを採択した。
C11規格では、型ジェネリックマクロ、匿名構造体、Unicodeサポートの改善、アトミック操作、マルチスレッド、境界チェック関数など、C言語とライブラリに多数の新機能が追加されています。また、既存のC99ライブラリの一部をオプション化し、C++との互換性も向上させています。標準マクロは、C11サポートが利用可能であることを示すため__STDC_VERSION__に定義されています。201112L
C17は、2018年6月に発行されたC言語の標準規格であるISO/IEC 9899:2018の非公式な名称です。この規格では、新しい言語機能は導入されておらず、技術的な修正とC11の不具合の明確化のみが行われます。標準マクロは、C17がサポートされていることを示す__STDC_VERSION__ように定義されています201710L。
C23 は、現在の主要な C 言語標準改訂版の非公式な名称です。開発の大部分は「C2X」として知られていました。過去のリリースをベースに、新しいキーワード、変数宣言時の型推論autoを提供するための追加の意味、およびを含む新しい型、標準ライブラリの拡張などの機能が導入されています。[ 31 ]nullptr_t_BitInt(N)
C23は2024年10月にISO/IEC 9899:2024として発行されました。[ 32 ]標準マクロは、C23のサポートが利用可能であることを示すよう__STDC_VERSION__に定義されています202311L。
C29 (C2Y) は、C23 (C2X) に続く次の主要な C 言語標準改訂版の非公式な名称であり、2020 年代中にリリースされることが期待されているため、「C2Y」の「2」が付けられています。C2Y の初期作業草案は、2024 年 2 月に作業グループISO/IEC JTC1/SC22 /WG14 によって N3220 としてリリースされました。[ 33 ]
歴史的に、組み込みC言語プログラミングでは、固定小数点演算、複数の独立したメモリバンク、基本的な入出力操作といった特殊な機能をサポートするために、C言語に対する非標準的な拡張機能が必要とされてきた。
2008年、C標準委員会は、すべての実装が準拠すべき共通標準を提供することでこれらの問題に対処するため、 C言語を拡張する技術レポート[ 34 ]を発表しました。これには、固定小数点演算、名前付きアドレス空間、基本的なI/Oハードウェアアドレッシングなど、通常のCでは利用できない多くの機能が含まれています。
C には、C 標準で規定された形式文法があります。 [ 35 ]行末は一般的に C では重要ではありませんが、行境界は前処理段階では重要です。コメントは、区切り文字/*との間*/、または (C99 以降)//行末まで続く の間に記述できます。と で区切られたコメントは/*ネストされず、これらの文字シーケンスは文字列*/または文字リテラルの中にある場合、コメント区切り文字として解釈されません。[ 36 ]
C言語のソースファイルには、宣言と関数定義が含まれています。関数定義には、宣言とステートメントが含まれています。宣言ではstruct、、、unionなどのキーワードを使用して新しい型を定義するenumか、型に変数名を付けて新しい変数のメモリ領域を確保します。通常、型名の後に変数名を記述します。charやなどのキーワードはint、組み込み型を指定します。コードのセクションは、宣言の範囲を制限し、制御構造に対して単一のステートメントとして機能するように、中括弧({および}、いわゆる「波括弧」)で囲まれます。
命令型言語である C では、ステートメントを使用してアクションを指定します。最も一般的なステートメントは式ステートメントで、評価する式とセミコロンで構成されます。評価の副作用として、関数が呼び出されたり、変数に新しい値が割り当てられたりする場合があります。ステートメントの通常の逐次実行を変更するために、C には予約語で識別されるいくつかの制御フローステートメントが用意されています。構造化プログラミングifは、... [ else] 条件付き実行と、do... while、、whileおよびfor反復実行 (ループ)によってサポートされています。forステートメントには、初期化、テスト、および再初期化の式が別々にあり、これらのいずれかまたはすべてを省略できます。breakおよびはcontinueループ内で使用できます。break は最も内側の囲みループステートメントを抜けるために使用され、continue は再初期化にスキップするために使用されます。また、関数内のgoto指定されたラベルに直接分岐する非構造化ステートメントもあります。は、整数式の値に基づいて実行するをswitch選択します。他の多くの言語とは異なり、制御フローはで終了しない限り、次のにフォールスルーします。casecasebreak
式では、さまざまな組み込み演算子を使用でき、関数呼び出しを含めることができます。関数の引数とほとんどの演算子のオペランドが評価される順序は規定されていません。評価はインターリーブされることもあります。ただし、すべての副作用(変数への格納を含む)は次の「シーケンスポイント」の前に発生します。シーケンスポイントには、各式ステートメントの終了、および各関数呼び出しの開始と終了が含まれます。シーケンスポイントは、特定の演算子(&&、、||および?:コンマ演算子)を含む式の評価中にも発生します。これにより、コンパイラによるオブジェクトコードの高度な最適化が可能になりますが、C プログラマは、他のプログラミング言語よりも信頼性の高い結果を得るために、より注意を払う必要があります。
カーニハンとリッチーは『C プログラミング言語の序論』の中で、「C 言語も他の言語と同様に欠点がある。演算子の中には優先順位が間違っているものや、構文の一部を改善できるものがある」と述べている。[ 37 ] C 標準では、既存のソフトウェアへの影響を考慮して、これらの欠点の多くを修正しようとはしなかった。
基本的なCソース文字セットには、次の文字が含まれます。[ 38 ]
a– z、A–Z0–9! " # % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ { | } ~改行文字はテキスト行の終わりを示します。必ずしも実際の1文字に対応する必要はありませんが、便宜上、C言語では1文字として扱われます。
POSIX規格では、C言語の基本ソース文字セットにいくつかの文字(特に「@」)を追加した移植性の高い文字セットが規定されています。どちらの規格も特定の値エンコーディングを規定していません。ASCIIとEBCDICはどちらも、少なくともこれらの基本文字を含んでいるため、これらの規格に準拠しています。ただし、これらの文字には異なるエンコード値を使用しています。
文字列リテラルでは追加のマルチバイトエンコード文字を使用できますが、それらは完全に移植可能ではありません。C99以降、多\uXXXX国籍Unicode文字は、または\UXXXXXXXXエンコード(はX16進数文字を表します)を使用してCソーステキスト内に移植可能に埋め込むことができます。
基本的なC言語の実行文字セットには、同じ文字に加えて、ヌル文字、アラート、バックスペース、キャリッジリターンの表現が含まれています。[ 38 ]
C言語規格の改訂ごとに、拡張文字セットの実行時サポートが向上してきた。
C言語のすべてのバージョンには、大文字と小文字を区別する予約語があります。予約語であるため、変数名には使用できません。
C89には32個の予約語があります。
C99ではさらに5つの予約語が追加されました(‡はC23キーワードの代替スペルエイリアスを示します)。
C11ではさらに7つの予約語が追加されました。[ 39 ](‡はC23キーワードの別の綴りの別名を示します)
_Alignas‡_Alignof‡_Atomic_Generic_Noreturn_Static_assert‡_Thread_local‡C23はさらに15語を残した。
alignasalignofboolconstexprfalsenullptrstatic_assertthread_localtruetypeoftypeof_unqual_BitInt_Decimal32_Decimal64_Decimal128最近予約された単語のほとんどは、アンダースコアの後に大文字が続く形で始まります。これは、この形式の識別子が以前はC標準で実装専用に予約されていたためです。既存のプログラムソースコードはこれらの識別子を使用していなかったため、C実装がこれらのプログラミング言語の拡張機能をサポートし始めても影響を受けません。一部の標準ヘッダーでは、アンダースコア付き識別子のより便利な同義語が定義されています。これらの単語の一部は、C23で従来の綴りでキーワードとして追加され、対応するマクロは削除されました。
C89 より前は、entryキーワードとして予約されていました。C89 として知られるようになったものを解説した彼らの著書『The C Programming Language』の第 2 版で、カーニハンとリッチーは、「以前は予約されていたが一度も使用されなかったキーワードはentry、もはや予約されていません。」および「生まれなかったentryキーワードは撤回されました。」と書いています。 [ 40 ]
C言語は豊富な演算子セットをサポートしています。演算子とは、式を評価する際に実行される操作を指定するために式内で使用される記号です。C言語には以下の演算子があります。
+、、、、-*/%=+=, , , , , , , , , -= *= /= %= &= |= ^= <<= >>=~、、、&|^<<>>!、、&&||? :==、!=( )++、--.、->sizeoftypeof、typeof_unqualC23以降<、<=、>、>=&、、*[ ],( )(typename)C 言語では、 FortranやPL/I=の慣例に従い、代入を示すために演算子 (数学で等価性を表すために使用) を使用しますが、ALGOLやその派生言語とは異なります。C 言語では、等価性をテストするために演算子を使用します。代入演算子と等価性演算子の類似性により、誤って一方を他方の代わりに使用してしまうことがあり、多くの場合、この間違いはエラー メッセージを生み出しません (ただし、一部のコンパイラは警告を生成します)。たとえば、条件式を誤って と記述すると、代入後のの値が でない限り、 と評価されます。 [ 41 ]==if (a == b + 1)if (a = b + 1)truea0
C言語の演算子の優先順位は必ずしも直感的ではありません。たとえば、演算子は、(ビットごとのAND)演算子や(ビットごとのOR)演算子==よりも強く結合し(先に実行されます)、式は、それがコーダーの意図であるかのように記述する必要があります。 [ 42 ]&|x & 1 == 0(x & 1) == 0

C の型システムは静的で弱型付けであるため、PascalなどのALGOLの派生言語の型システムに似ています。[ 43 ]さまざまなサイズの整数 (符号付きと符号なし)、浮動小数点数、列挙型 ( )の組み込み型があります。整数型は、1 バイト文字によく使用されます。C99 では、ブールデータ型が追加されました。配列、ポインタ、レコード( )、共用体( )などの派生型もあります。enumcharstructunion
C言語は、型システムからのエスケープが必要となる低レベルシステムプログラミングでよく使用されます。コンパイラはほとんどの式の型が正しいことを保証しようとしますが、プログラマは型キャストを使用して値をある型から別の型に明示的に変換したり、ポインタや共用体を使用してデータオブジェクトの基となるビットを別の方法で再解釈したりするなど、さまざまな方法でチェックをオーバーライドできます。
C言語の宣言構文は直感的ではないと感じる人もいる。特に関数ポインタに関してはそうだ。(リッチーの考えは、識別子をその使用状況に似たコンテキストで宣言することだった。「宣言は使用状況を反映する」)。[ 44 ]
C言語の一般的な算術変換は効率的なコード生成を可能にする一方で、予期せぬ結果を生み出す場合もあります。例えば、同じ幅の符号付き整数と符号なし整数を比較する場合、符号付き値を符号なしに変換する必要があります。符号付き値が負の場合、この変換によって予期せぬ結果が生じる可能性があります。
C言語はポインタの使用をサポートしています。ポインタは、メモリ内のオブジェクトまたは関数のアドレスまたは位置を記録する参照の一種です。ポインタは逆参照することで、指し示すアドレスに格納されているデータにアクセスしたり、指し示す関数を呼び出したりすることができます。ポインタは、代入演算またはポインタ演算を使用して操作できます。ポインタ値の実行時表現は通常、生のメモリ アドレス(場合によってはワード内のオフセット フィールドが追加される)ですが、ポインタの型には指し示す対象の型が含まれるため、ポインタを含む式はコンパイル時に型チェックできます。ポインタ演算は、指し示すデータ型のサイズに応じて自動的にスケーリングされます。
C言語ではポインタは多くの用途に使用されます。テキスト文字列は、文字配列へのポインタを使用して操作されるのが一般的です。動的メモリ割り当てはポインタを使用して実行され、その結果はmalloc通常、格納するデータのデータ型にキャストされます。ツリーなどの多くのデータ型は、ポインタを使用してリンクされた動的に割り当てられたオブジェクトとして実装されるのが一般的ですstruct。他のポインタへのポインタは、多次元配列やオブジェクトの配列でよく使用されますstruct。関数へのポインタ(関数ポインタ)は、関数を高階関数( qsortやbsearchなど)への引数として渡したり、ディスパッチテーブルで使用したり、イベントハンドラへのコールバックとして使用したりするのに便利です。[ 18 ]
ヌルポインタ値は、有効な場所を明示的に指していません。ヌルポインタ値の逆参照は未定義であり、多くの場合、セグメンテーション違反が発生します。ヌルポインタ値は、リンクリストの最後のノードに「next」ポインタがない場合などの特殊なケースを示す場合や、ポインタを返す関数からのエラー表示として役立ちます。ソースコード内の適切なコンテキスト(ポインタ変数への代入など)では、ヌルポインタ定数は0、ポインタ型への明示的なキャストの有無にかかわらず、NULLいくつかの標準ヘッダーで定義されているマクロ、またはC23以降は定数とともに、として記述できますnullptr。条件付きコンテキストでは、ヌルポインタ値はに評価されfalse、他のすべてのポインタ値はに評価されますtrue。
void ポインタ ( void *) は型が指定されていないオブジェクトを指し、そのため「汎用」データ ポインタとして使用できます。指し示すオブジェクトのサイズと型が不明なため、void ポインタを逆参照したり、ポインタ演算を実行したりすることはできませんが、他のオブジェクト ポインタ型との間で簡単に変換できます (多くのコンテキストでは暗黙的に変換されます)。[ 18 ]
ポインタを不用意に使用すると、潜在的に危険です。ポインタは通常チェックされないため、任意の場所を指すようにすることができ、望ましくない影響を引き起こす可能性があります。適切に使用されたポインタは安全な場所を指しますが、無効なポインタ演算を使用したり、ポインタが指すオブジェクトが解放後も使用され続けたり(ダングリングポインタ)、初期化されずに使用されたり(ワイルドポインタ)、キャスト、共用体、または別の不正なポインタを介して安全でない値を直接割り当てたりすることで、安全でない場所を指すようにすることができます。一般的に、C言語はポインタ型の操作と変換を許容しますが、コンパイラは通常、さまざまなレベルのチェックオプションを提供します。他のプログラミング言語の中には、より制限的な参照型を使用することでこれらの問題に対処しているものもあります。
C言語における配列型は、従来、コンパイル時に指定される固定サイズでした。より新しいC99規格では、可変長配列も認められています。しかし、標準ライブラリの関数を用いて、実行時に任意のサイズのメモリブロックを割り当てmalloc、それを配列として扱うことも可能です。
配列は常に(実質的に)ポインタを介してアクセスされるため、配列へのアクセスは通常、基となる配列のサイズに対してチェックされませんが、一部のコンパイラでは境界チェックをオプションとして提供する場合があります。[ 45 ] [ 46 ]そのため、配列の境界違反が発生する可能性があり、不正なメモリアクセス、データの破損、バッファオーバーフロー、実行時例外など、さまざまな影響が生じる可能性があります。
C 言語には多次元配列を宣言するための特別な規定はありませんが、型システム内の再帰を利用して配列の配列を宣言することで、実質的に同じことを実現しています。結果として得られる「多次元配列」のインデックス値は、行優先順で増加すると考えることができます。多次元配列は、行列を格納するために数値アルゴリズム (主に応用線形代数) でよく使用されます。C 配列の構造は、この特定のタスクに適しています。ただし、C の初期バージョンでは、配列の境界は既知の固定値であるか、またはそれを必要とするサブルーチンに明示的に渡す必要があり、動的にサイズ変更される配列の配列には、二重インデックスを使用してアクセスできませんでした。(この問題を回避するために、列へのポインタの追加の「行ベクトル」を使用して配列を割り当てました。) C99 では、この問題を解決する「可変長配列」が導入されました。
以下の例は、最新のC言語(C99以降)を使用して、ヒープ上に2次元配列を割り当て、アクセスに多次元配列インデックスを使用する方法を示しています(多くのCコンパイラでは境界チェックを使用できます)。
int func ( int n , int m ) {float ( * p )[ n ][ m ] = malloc ( sizeof * p );if ( p == NULL ) {-1を返す;}for ( int i = 0 ; i < n ; i ++ ) {for ( int j = 0 ; j < m ; j ++ ) {( * p )[ i ][ j ] = i + j ;}}print_array ( n , m , p );無料(p )1を返す;}そして、C99のAuto VLA機能を使用した同様の実装例を以下に示します。[ f ]
int func ( int n , int m ) {// 注意: n * m * sizeof(float) が自動 VLA の制限を超えず、スタックの利用可能なサイズ内に収まるようにチェックする必要があります。float p [ n ][ m ]; // auto VLA はスタック上に保持され、関数が呼び出されたときにサイズが設定されますfor ( int i = 0 ; i < n ; i ++ ) {for ( int j = 0 ; j < m ; j ++ ) {p [ i ][ j ] = i + j ;}}print_array ( n , m , p );// 関数が終了するとスタックフレームの残りの部分とともに消えるので、free(p) を呼び出す必要はありません1を返す;}添え字表記x[i]( はxポインタを表す)は のシンタックスシュガー*(x+i)です。[ 47 ]コンパイラのポインタ型に関する知識を利用して、 がx + i指すアドレスは、 が指すベースアドレスをバイトxだけインクリメントしたものではなく、が指す要素のサイズを 倍したiベースアドレスをインクリメントしたものとして定義されます。したがって、 は配列の 番目の要素を表します。ixx[i]i+1
さらに、ほとんどの式コンテキスト(例外として、演算子のオペランドとして使用される場合もありますsizeof)では、配列型の式は自動的に配列の最初の要素へのポインタに変換されます。これは、関数の引数として配列が指定された場合、配列全体がコピーされることはなく、最初の要素のアドレスのみが渡されることを意味します。したがって、C言語の関数呼び出しは値渡しセマンティクスを使用しますが、配列は実質的に参照渡しされます。
配列の合計サイズは、配列型の式にx適用することで決定できます。要素のサイズは、配列の参照解除された要素に演算子を適用することで決定できます。したがって、宣言された配列の要素数は、として決定できます。ただし、上記の自動変換のためにCコードでは最初の要素へのポインタしか利用できない場合がよくありますが、その場合は配列の完全な型と長さに関する情報は失われることに注意してください。sizeofsizeofAn = sizeof A[0]Asizeof A / sizeof A[0]
プログラミング言語の最も重要な機能の 1 つは、メモリとメモリに格納されているオブジェクトを管理するための機能を提供することです。C 言語では、オブジェクトにメモリを割り当てるための 3 つの主要な方法が提供されています。[ 18 ]
mallocと呼ばれるメモリ領域からライブラリ関数などを使用して実行時に要求できます。これらのブロックは、ライブラリ関数またはを呼び出して後で再利用するために解放されるまで保持されます。reallocfreeこれら3つのアプローチは、それぞれ異なる状況に適しており、様々なトレードオフがあります。例えば、静的メモリ割り当ては割り当てオーバーヘッドがほとんどなく、自動割り当ては若干オーバーヘッドが大きくなる可能性があり、動的メモリ割り当ては割り当てと解放の両方で大きなオーバーヘッドが発生する可能性があります。静的オブジェクトの永続性は、関数呼び出し間で状態情報を維持するのに役立ち、自動割り当ては使いやすいものの、スタック領域は通常、静的メモリやヒープ領域よりもはるかに制限が多く、一時的なものです。また、動的メモリ割り当てでは、実行時にのみサイズが判明するオブジェクトを簡単に割り当てることができます。ほとんどのCプログラムは、これら3つすべてを幅広く利用しています。
可能な限り、自動割り当てまたは静的割り当てが最も簡単です。これは、ストレージがコンパイラによって管理されるため、プログラマが手動でストレージを割り当てたり解放したりする、エラーが発生しやすい作業から解放されるためです。しかし、多くのデータ構造は実行時にサイズが変わる可能性があり、静的割り当て(およびC99以前の自動割り当て)はコンパイル時に固定サイズでなければならないため、動的割り当てが必要となる状況が数多くあります。[ 18 ] C99規格以前は、可変サイズの配列が一般的な例でした。(動的に割り当てられた配列の例については、 C言語の動的メモリ割り当てに関する記事を参照してください。)実行時に制御不能な結果を招く可能性のある自動割り当てとは異なり、動的割り当て関数は、必要なストレージを割り当てられない場合に、その旨を示す(ヌルポインタ値の形式)応答を返します。(大きすぎる静的割り当ては、通常、プログラムの実行が開始される前にリンカまたはローダによって検出されます。)
特に指定がない限り、静的オブジェクトはプログラム起動時にゼロまたはヌルポインタ値を持ちます。自動的および動的に割り当てられたオブジェクトは、初期値が明示的に指定されている場合にのみ初期化されます。そうでない場合、初期値は不定値になります(通常は、ストレージに存在するビットパターンであり、その型に対して有効な値を表していない可能性があります)。プログラムが初期化されていない値にアクセスしようとすると、結果は未定義です。多くの最新のコンパイラはこの問題を検出して警告しようとしますが、誤検出と見逃しの両方が発生する可能性があります。
ヒープメモリの割り当ては、可能な限り再利用するために、プログラム内での実際の使用と同期させる必要があります。たとえば、ヒープメモリへの唯一のポインタがスコープ外になったり、明示的に解放される前に値が上書きされたりすると、そのメモリは後で再利用するために回復できず、実質的にプログラムから失われます。これはメモリリークと呼ばれる現象です。逆に、メモリが解放された後も参照される可能性があり、予期しない結果につながることがあります。通常、障害の症状は、エラーの原因となるコードとは無関係なプログラムの一部に現れるため、障害の診断が困難になります。このような問題は、自動ガベージコレクションを備えた言語では軽減されます。
C プログラミング言語は、拡張の主要な方法としてライブラリを使用します。C では、ライブラリは単一の「アーカイブ」ファイルに含まれる関数の集合です。各ライブラリには通常、ヘッダーファイルがあり、プログラムで使用できるライブラリ内の関数のプロトタイプと、これらの関数で使用される特殊なデータ型とマクロシンボルの宣言が含まれています。プログラムがライブラリを使用するには、ライブラリのヘッダーファイルを含める必要があり、ライブラリをプログラムにリンクする必要があります。多くの場合、これにはコンパイラフラグ(たとえば、-lm「数学ライブラリをリンクする」の省略形) が必要です。[ 18 ]
最も一般的なCライブラリはC標準ライブラリであり、これはISOおよびANSI C規格で規定され、すべてのC実装に付属しています(組み込みシステムなどの限定された環境を対象とする実装では、標準ライブラリの一部のみが提供される場合があります)。このライブラリは、ストリーム入出力、メモリ割り当て、数学演算、文字列、および時間値をサポートしています。いくつかの個別の標準ヘッダー(例stdio.h:)は、これらの機能やその他の標準ライブラリ機能のインターフェースを規定しています。
Cライブラリ関数のもう一つの一般的なセットは、 UnixおよびUnixライクなシステムを対象としたアプリケーションで使用される関数、特にカーネルへのインターフェースを提供する関数です。これらの関数は、 POSIXやSingle UNIX Specificationなどの様々な標準規格で詳細に規定されています。
C言語で書かれたプログラムが多数存在するため、さまざまなライブラリが利用可能です。ライブラリはC言語で書かれることが多いのは、Cコンパイラが効率的なオブジェクトコードを生成するためです。プログラマは、 Java、Perl、Pythonなどの高レベル言語からルーチンを使用できるように、ライブラリへのインターフェースを作成します。[ 18 ]
ファイル入出力 (I/O) は C 言語自体の一部ではなく、ライブラリ (C 標準ライブラリなど) およびそれらに関連付けられたヘッダー ファイル (例: ) によって処理されます。ファイル処理は一般的に、ストリームstdio.hを介して動作する高レベル I/O によって実装されます。この観点から、ストリームはデバイスに依存しないデータ フローであり、ファイルは具体的なデバイスです。高レベル I/O は、ストリームとファイルの関連付けによって行われます。C 標準ライブラリでは、バッファ(メモリ領域またはキュー) が、データが最終的な宛先に送信される前に一時的にデータを格納するために使用されます。これにより、ハード ドライブやソリッド ステート ドライブなどの低速デバイスを待つ時間が短縮されます。低レベル I/O 関数は標準 C ライブラリの一部ではありませんが、一般的に「ベア メタル」プログラミング (ほとんどの組み込みプログラミングのように、オペレーティングシステムに依存しないプログラミング) の一部です。ごく少数の例外を除いて、実装には低レベル I/O が含まれています。
C言語プログラマーが、コンパイラが提供するよりも厳密な方法で、未定義の動作を持つ文や誤った式を含む可能性のある文を見つけて修正するのに役立つツールが数多く開発されている。
Lintなどの自動ソースコードチェックおよび監査ツールが存在します。一般的な方法としては、プログラムを最初に記述する際に Lint を使用して疑わしいコードを検出することです。プログラムが Lint を通過すると、C コンパイラを使用してコンパイルされます。また、多くのコンパイラは、構文的に有効であっても実際にはエラーである可能性のある構造についてオプションで警告することができます。MISRA Cは、組み込みシステム向けに開発された、そのような疑わしいコードを回避するための独自のガイドラインです。[ 48 ]
また、配列の境界チェック、バッファオーバーフローの検出、シリアライゼーション、動的メモリ追跡、自動ガベージコレクションなど、C言語の標準機能ではないアクションを実行するためのコンパイラ、ライブラリ、オペレーティングシステムレベルのメカニズムも存在します。
PurifyやValgrindのようなメモリ管理チェックツールや、メモリ割り当て関数の特別なバージョンを含むライブラリとのリンクは、メモリ使用における実行時エラーの発見に役立ちます。[ 49 ] [ 50 ]
C言語は、エンドユーザーおよびシステムレベルのアプリケーションの実装に広く使用されてきました。[ 51 ]

C言語は、オペレーティングシステムや組み込みシステムアプリケーションの実装におけるシステムプログラミングに広く用いられています。[ 52 ]これにはいくつかの理由があります。
malloc方式や、アリーナfreeを用いたより高度なメカニズム、あるいはDMA、割り込みハンドラ内での使用、仮想メモリシステムとの統合に適したOSカーネル用バージョンなど、さまざまなメモリ割り当て方式の使用と実装が可能です。コンピュータゲームは、多くの場合、複数の言語を組み合わせて作られています。C言語は、特にコンピュータプラットフォームから最高のパフォーマンスを引き出そうとするゲームにおいて重要な役割を果たしてきました。例としては、1993年のDoomが挙げられます。 [ 53 ]
歴史的に、C は、Web アプリケーション、サーバー、およびブラウザー間の情報の「ゲートウェイ」としてCommon Gateway Interface (CGI)を使用してWeb 開発に使用されることがありました。 [ 54 ] C は、その速度、安定性、およびほぼ普遍的な利用可能性のために、インタプリタ言語よりも選択された可能性があります。 [ 55 ] Web 開発を C で行うことはもはや一般的ではなく、[ 56 ]他の多くのWeb 開発言語が人気です。C ベースの Web 開発が継続されているアプリケーションには、ルーター、IoTデバイスなどのHTTP設定ページが含まれますが、ここでも一部のプロジェクトには、 OpenWRTでのLuaの使用など、より高レベル言語の一部が含まれています。
Apache HTTP ServerとNginxという2つの人気のあるWebサーバーはC言語で書かれています。[ 57 ] [ 58 ] C言語のハードウェアに近いアプローチにより、これらの高性能ソフトウェアシステムを構築できます。[ 59 ]
C言語は、他の言語の実装において中間言語として使用されることがあります。この方法は、移植性や利便性のために用いられることがあります。C言語を中間言語として使用することで、マシン固有のコード生成器を追加で用意する必要がなくなります。C言語には、行番号プリプロセッサディレクティブや初期化リスト末尾のオプションの余分なカンマなど、生成されたコードのコンパイルをサポートする機能がいくつかあります。しかし、C言語のいくつかの欠点から、C--など、中間言語としての使用を目的とした他のC言語ベースの言語が開発されるようになりました。また、現代の主要なコンパイラであるGCCとLLVMはどちらもC言語以外の中間表現を備えており、これらのコンパイラはC言語を含む多くの言語のフロントエンドをサポートしています。
C言語は、ハードウェアからの抽象化層が薄く、オーバーヘッドも低いため、プログラマーがアルゴリズムやデータ構造を効率的に実装することを可能にします。これは、計算負荷の高いプログラムにとって重要な基準です。例えば、GNU多倍長演算ライブラリ、GNU科学ライブラリ、Mathematica、MATLABは、全部または一部がC言語で記述されています。多くの言語がC言語のライブラリ関数呼び出しをサポートしています。例えば、PythonベースのフレームワークであるNumPyは、高性能化やハードウェアとの連携にC言語を使用しています。
C言語の普及と効率性の結果、他のプログラミング言語のコンパイラ、ライブラリ、インタプリタはしばしばC言語で実装されています。 [ 60 ]例えば、Python [ 61 ]、Perl [ 62 ]、Ruby [ 63 ]、PHP [ 64 ]のリファレンス実装はC言語で書かれています。
リッチー自身も自分が作った言語の限界について冗談を言っていた。[ 65 ]
アセンブリ言語の力と利便性...アセンブリ言語
—デニス・リッチー
C言語は人気があり、影響力があり、非常に成功している一方で、以下のような欠点も抱えている。
malloc、free間違いを起こしやすい。不適切な使用は、メモリリークやダングリングポインタにつながる可能性がある。[ 66 ]scanfまたは)は、バッファオーバーランstrncatを引き起こす可能性があります。#pragma規約、より大きな整数内の異なるバイト順序(エンディアンを含む)など)のサポートには、標準化が限られています。多くの言語実装では、これらのオプションの一部はプリプロセッサディレクティブ[ 68 ] [ 69 ]で処理され、一部は追加のキーワード(例:__cdecl呼び出し規約の使用)で処理されます。ディレクティブとオプションは一貫してサポートされているわけではありません。[ 70 ]evalJavaScriptなど)、ガベージコレクションなどを直接サポートしていません。setjmp標準ライブラリ関数longjmp[ 72 ]を使用して、マクロを介してtry-catchメカニズムを実装しています。また、gotoエラー処理にはステートメントがよく使用されます。目的によっては、望ましくない動作の機会を減らすために、 MISRA CやCERT Cなどの制限付き C スタイルが採用されています。 [ 73 ] CWEなどのデータベースは、一般的にシステム、特に C でコーディングされたシステムに潜在的な脆弱性がある方法をカウントし、緩和策の推奨事項を提供します。
こうした欠点の一部を軽減できるツールが存在する。現代のCコンパイラには、多くの潜在的なバグを特定するのに役立つ警告を生成するチェック機能が含まれている。
C言語におけるポインタの使用は、 CHERIやPermission Overlay Extensionsといった命令セットアーキテクチャ拡張機能を用いることで、よりリスクの少ないものにすることができます。これらの技術は、ハードウェアレベルでポインタの基本的な性質を変更し、境界チェックや目的を持たせることで、バッファオーバーフローや不適切なヒープアクセスを防ぐのに役立ちます。
2020年代初頭から、Linuxカーネルには安全性を向上させるための特別な対策が施された言語であるRustで書かれた部分がある。 [ 74 ]

C 以降に開発された多くの言語は、C++、C#、C シェル、D、Go、Java、JavaScript、Julia、Limbo、LPC、Objective-C、Perl、PHP、Python、Ruby、Rust、Swift 、 Verilog、SystemVerilogなど、C の影響を受け、C の側面を取り入れています。[ 8 ] [ 75 ]最も広範な影響は構文的なもので、これらの言語は C のステートメントと式の構文を、C とは異なる、時には根本的に異なる型システム、データ モデル、大規模プログラム構造と組み合わせていると主張する人もいます。
ChやCINTなど、C言語またはC言語に近い言語で記述できるインタプリタがいくつか存在し、これらはスクリプト作成にも使用できる。
オブジェクト指向プログラミング言語が普及したとき、 C++とObjective-Cは、オブジェクト指向機能を提供するCの2つの異なる拡張言語でした。どちらの言語も元々はソース間コンパイラとして実装されていました。ソースコードはCに変換され、その後Cコンパイラでコンパイルされました。[ 76 ]
C ++プログラミング言語 (当初は「クラス付き C 」と呼ばれていました) は、C のような構文でオブジェクト指向機能を提供するアプローチとして、ビャルネ・ストロヴストルップによって考案されました。 [ 77 ] C++ は、オブジェクト指向プログラミングに役立つ型付けの強度、スコープ、その他のツールを追加し、テンプレートによる汎用プログラミングを可能にします。C のほぼスーパーセットである C++ は、いくつかの例外を除いて、現在ではC のほとんどをサポートしています。
Objective-Cは元々C言語の上に薄いレイヤーとして構築されたもので、現在もC言語の厳密な上位互換であり、動的型付けと静的型付けを組み合わせたハイブリッドなパラダイムを用いたオブジェクト指向プログラミングを可能にしています。Objective-Cの構文はC言語とSmalltalkの両方から派生しており、前処理、式、関数宣言、関数呼び出しに関わる構文はC言語から継承され、オブジェクト指向機能の構文は元々Smalltalkから採用されました。
C++とObjective-Cに加えて、Ch、Cilk、およびUnified Parallel Cは、ほぼCの上位互換と言える。
0print_arrayの型が異なるため、若干異なります。malloc 版では 2D 配列へのポインタですが、自動 VNA 版では単なる 2D 配列です。1980年代:Verilogが初めて導入される。VerilogはC言語に触発された。