私は C の初心者で、C で遊んでいました。次のような C コードを入力しました。
#include <stdio.h>
int main()
{
printf("hello world\n");
\
return 0;
}
意識して使っていたにもかかわらず\
、C コンパイラはエラーをスローしません。この記号は C 言語で何に使用されますか?
編集:
これでも機能します:
"\n";
私は C の初心者で、C で遊んでいました。次のような C コードを入力しました。
#include <stdio.h>
int main()
{
printf("hello world\n");
\
return 0;
}
意識して使っていたにもかかわらず\
、C コンパイラはエラーをスローしません。この記号は C 言語で何に使用されますか?
編集:
これでも機能します:
"\n";
バックスラッシュと改行のシーケンスは、翻訳プロセスの非常に早い段階 (フェーズ 2) でコードから削除されます。これは、文字列の連結が行われる前に長い文字列リテラルを作成する方法であり、マクロを複数行に拡張する方法でもあります。
C99 標準の §5.1.1.2 Translation Phases を参照してください。
変換の構文規則間の優先順位は、次のフェーズによって指定されます。5)
- 物理ソース ファイルのマルチバイト文字は、必要に応じて、実装定義の方法でソース文字セットにマップされます (行末インジケーターに改行文字を導入します)。Trigraph シーケンスは、対応する単一文字の内部表現に置き換えられます。
\
直後に改行文字が続くバックスラッシュ文字 ( ) の各インスタンスが削除され、物理ソース行が結合されて論理ソース行が形成されます。物理ソース行の最後のバックスラッシュのみが、そのようなスプライスの一部として適格です。空でないソース ファイルは、改行文字で終了する必要があります。そのようなスプライシングが行われる前に、直前にバックスラッシュ文字を付けてはなりません。- ソースファイルは、前処理トークン6)と一連の空白文字 (コメントを含む)に分解されます。ソース ファイルは、部分的な前処理トークンまたは部分的なコメントで終わってはなりません。各コメントは、1 つの空白文字に置き換えられます。改行文字は保持されます。改行以外の空白文字の各空でないシーケンスが保持されるか、1 つの空白文字に置き換えられるかは、実装によって定義されます。
- 前処理ディレクティブが実行され、マクロ呼び出しが展開され、
_Pragma
単項演算子式が実行されます。ユニバーサル文字名の構文に一致する文字シーケンスがトークン連結 (6.10.3.3) によって生成される場合、動作は未定義です。前処理ディレクティブにより、指定された#include
ヘッダーまたはソース ファイルがフェーズ 1 からフェーズ 4 まで再帰的に処理されます。その後、すべての前処理ディレクティブが削除されます。- 文字定数および文字列リテラル内の各ソース文字セット メンバーおよびエスケープ シーケンスは、実行文字セットの対応するメンバーに変換されます。対応するメンバーがない場合は、ヌル (ワイド) 文字以外の実装定義のメンバーに変換されます。7)
- 隣接する文字列リテラル トークンは連結されます。
- トークンを区切る空白文字は重要ではなくなりました。各前処理トークンはトークンに変換されます。結果のトークンは、構文的および意味的に分析され、翻訳単位として翻訳されます。
- すべての外部オブジェクトおよび関数参照が解決されます。ライブラリ コンポーネントは、現在の翻訳で定義されていない関数やオブジェクトへの外部参照を満たすためにリンクされています。このようなトランスレータの出力はすべて、実行環境での実行に必要な情報を含むプログラム イメージに収集されます。
5)実装は、これらの個別のフェーズが発生するかのように動作する必要がありますが、実際には多くのフェーズが通常一緒に折り畳まれます。
6) 6.4 で説明されているように、ソース ファイルの文字を前処理トークンに分割するプロセスは、コンテキストに依存します。たとえば、前処理ディレクティブ
<
内の の処理を参照してください。#include
7)実装は、対応しないすべてのソース文字を同じ実行文字に変換する必要はありません。
バックスラッシュの後に空白やその他の文字があると、コンパイル エラーが発生します。コンパイル エラーがないため、その後に何もないことがわかります。
あなたの質問の他の部分、約:
"\n";
はかなり異なります。これは、副作用のない単純な式であるため、プログラムには影響しません。オプティマイザーはそれを完全に破棄します。あなたが書くとき:
i = 1;
破棄される値を持つ式があります。変更の副作用について評価されi
ます。
場合によっては、次のようなコードが見つかります。
*ptr++;
コンパイラは、式の結果が破棄されることを警告します。式は次のように簡略化できます。
ptr++;
プログラムでも同じ効果が得られます。
の\
直後に改行が続くと、前処理によって消費され、次の「物理」行が現在の論理行に結合されます。これは、長い前処理ディレクティブを作成する場合に非常に重要です。これらのディレクティブはすべて1つの論理行に配置する必要があります。
#define SHORT very log macro \
consisting of lots and \
lots of preprocessor \
tokens
バックスラッシュと改行のシーケンスを削除すると、正しくなくなります。Unixカルチャの他のいくつかの言語には、同様のバックスラッシュ行継続構文があります。Bourneシェルから派生したPOSIXシェル言語と、makefileです。
$ this is \
one shell command
について"\n";
、それは式ステートメントを形成するために使用される主要な式です。Cでは、式をステートメントとして使用でき、これは常に悪用されます。たとえばprintf
、呼び出しは式ステートメントです。printf("hello world\n")
関数を呼び出して戻り値を取得する接尾辞式です。この式をステートメントとして使用したため、戻り値は破棄されます。の戻り値はprintf
、印刷された文字数、またはそれが成功したかどうかを示します。したがって、それを破棄することにより、プログラムは、printf
呼び出しが実際に機能したかどうかを認識しなくなります。
式ステートメントの値は破棄されるため、そのようなステートメントにも副作用がない場合、それは何もしない(yourのように"\n"
)役に立たないステートメントです。しかし、そのような役に立たない式のステートメントは誤りではありません。コンパイラのコマンドラインに警告オプションを追加すると、「効果のないステートメント」などの警告が表示される場合があります。
バックスラッシュは単に次の文字をエスケープしています。この場合、おそらく行末 (CR) 文字です。完全に合理的です。
バックスラッシュ \ は、C プリプロセッサによって解釈されます。次の文字 (ケースの改行文字) を保護します。
バックスラッシュとそれに続くものはエスケープ シーケンスです。"\n" を一緒に使用すると、改行文字になります (改行を出力します)。もう 1 つの重要なものは、タブを表す "\t" です。