web-dev-qa-db-ja.com

プリプロセッサを使用した文字列の連結

前処理中に文字列を連結することは可能ですか?

この例を見つけました

#define H "Hello "
#define W "World!"
#define HW H W

printf(HW); // Prints "Hello World!"

しかし、それは私にとっては機能しません-gcc -std=c99を使用すると「Hello」と出力されます

[〜#〜] upd [〜#〜]この例は、現在機能しているように見えます。しかし、それはcプリプロセッサの通常の機能ですか?

21

隣接する文字列リテラルの連結はプリプロセッサの機能ではなく、コア言語(CおよびC++の両方)の機能です。あなたは書くことができます:

printf("Hello "
       " world\n");
40
AProgrammer

実際にプリプロセッサでトークンを連結することはできますが、トリッキーなので注意してください。キーは##演算子です。これをコードの最上部にスローする場合:

#define myexample(x,y,z) int example_##x##_##y##_##z## = x##y##z 

次に、基本的に、これが行うことは、前処理中に、次のようなそのマクロへの呼び出しを行うことです。

myexample(1,2,3);

そしてそれは文字通りに変わります

int example_1_2_3 = 123;

これにより、正しく使用すれば、コーディング中に多くの柔軟性が得られますが、使用方法に正確には適用されません。少しマッサージすれば、それを機能させることができます。

あなたの例の1つの可能な解決策は次のようになります:

#define H "Hello "
#define W "World!"
#define concat_and_print(a, b) cout << a << b << endl

そして、次のようなことをする

concat_and_print(H,W);
19
NDL

gcc online docs から:

'##'前処理演算子は、トークンの貼り付けを実行します。マクロが展開されると、各「##」演算子の両側にある2つのトークンが1つのトークンに結合され、マクロ展開内の「##」と2つの元のトークンが置き換えられます。

名前付きコマンドを解釈するCプログラムを考えてみましょう。コマンドのテーブル、おそらく次のように宣言された構造体の配列が必要です。

 struct command
 {
   char *name;
   void (*function) (void);
 };

 struct command commands[] =
 {
   { "quit", quit_command },
   { "help", help_command },
   ...
 };

各コマンド名を文字列定数で1回と関数名で1回の2回指定する必要がないほうがきれいです。コマンドの名前を引数として取るマクロは、これを不要にすることができます。文字列定数は文字列化で作成でき、関数名は引数を_commandと連結して作成できます。以下にその方法を示します。

 #define COMMAND(NAME)  { #NAME, NAME ## _command }

 struct command commands[] =
 {
   COMMAND (quit),
   COMMAND (help),
   ...
 };
12
user173973

なぜこれが機能するのかについての出典を引用する回答を追加すると思いました。

C99標準§5.1.1.2は、Cコードの変換フェーズを定義しています。第6項には、

  1. 隣接する文字列リテラルトークンが連結されます。

同様に、C++標準(ISO 14882)では、§2.1が変換のフェーズを定義しています。ここで、サブセクション6は次のように述べています。

6隣接する通常の文字列リテラルトークンが連結されます。隣接するワイド文字列リテラルトークンが連結されます。

これが、文字列を互いに隣接させるだけで連結できる理由です。

printf("string"" one\n");

>> ./a.out
>> string one

質問の前処理部分は、単に#define前処理ディレクティブは、識別子(H)から文字列("Hello ")。

6
Mike