Cでこのようなことをしなければなりません。charを使用した場合にのみ機能しますが、文字列が必要です。これどうやってするの?
#define USER "jack" // jack or queen
#if USER == "jack"
#define USER_VS "queen"
#elif USER == "queen"
#define USER_VS "jack"
#endif
Cでこのようなことをしなければなりません。charを使用した場合にのみ機能しますが、文字列が必要です。これどうやってするの?
#define USER "jack" // jack or queen
#if USER == "jack"
#define USER_VS "queen"
#elif USER == "queen"
#define USER_VS "jack"
#endif
回答:
プリプロセッサディレクティブで可変長文字列比較を完全に行う方法はないと思います。ただし、おそらく次のことを行うことができます。
#define USER_JACK 1
#define USER_QUEEN 2
#define USER USER_JACK
#if USER == USER_JACK
#define USER_VS USER_QUEEN
#elif USER == USER_QUEEN
#define USER_VS USER_JACK
#endif
または、コードを少しリファクタリングして、代わりにCコードを使用することもできます。
#define USER_VS (3 - USER)
、この特定のケースでは可能性があります。:)
[更新:2018.05.03]
警告:すべてのコンパイラが同じ方法でC ++ 11仕様を実装しているわけではありません。以下のコードは私がテストしたコンパイラで動作しますが、多くのコメント投稿者は別のコンパイラを使用していました。
Shafik Yaghmourの回答からの引用:コンパイル時のC文字列の長さの計算。これは本当にconstexprですか?
定数式はコンパイル時に評価されることが保証されていません。ドラフトC ++標準セクション5.19からの非規範的な引用のみがあります。
[...]> [注:定数式は翻訳中に評価できます。—文末注]
その言葉can
は世界にすべての違いをもたらします。
したがって、constexpr
コンパイラの作成者による仕様の解釈に応じて、この(または任意の)回答に関するYMMVが関係します。
[2016.01.31更新]
文字列の比較を必要とせずに目標を達成することでOPの全体的な側面を回避したため、以前の回答が気に入らなかった人もいるのでcompile time string compare
、ここでより詳細な回答を示します。
できません!C98またはC99にはありません。C11でもありません。MACRO操作の量がこれを変更することはありません。
でconst-expression
使用されるの定義は#if
文字列を許可しません。
文字を許可するので、文字に制限する場合は、次のように使用できます。
#define JACK 'J'
#define QUEEN 'Q'
#define CHOICE JACK // or QUEEN, your choice
#if 'J' == CHOICE
#define USER "jack"
#define USER_VS "queen"
#elif 'Q' == CHOICE
#define USER "queen"
#define USER_VS "jack"
#else
#define USER "anonymous1"
#define USER_VS "anonymous2"
#endif
#pragma message "USER IS " USER
#pragma message "USER_VS IS " USER_VS
あなたはできる!C ++ 11の場合。比較のためにコンパイル時ヘルパー関数を定義する場合。
// compares two strings in compile time constant fashion
constexpr int c_strcmp( char const* lhs, char const* rhs )
{
return (('\0' == lhs[0]) && ('\0' == rhs[0])) ? 0
: (lhs[0] != rhs[0]) ? (lhs[0] - rhs[0])
: c_strcmp( lhs+1, rhs+1 );
}
// some compilers may require ((int)lhs[0] - (int)rhs[0])
#define JACK "jack"
#define QUEEN "queen"
#define USER JACK // or QUEEN, your choice
#if 0 == c_strcmp( USER, JACK )
#define USER_VS QUEEN
#elif 0 == c_strcmp( USER, QUEEN )
#define USER_VS JACK
#else
#define USER_VS "unknown"
#endif
#pragma message "USER IS " USER
#pragma message "USER_VS IS " USER_VS
だから、最終的には、あなたがのために、最終的な文字列値を選択するあなたの目標accomlish方法変更する必要がありますUSER
とをUSER_VS
。
C99ではコンパイル時の文字列比較を行うことはできませんが、文字列のコンパイル時の選択は行うことができます。
本当にコンパイル時のsting比較を行う必要がある場合は、その機能を許可するC ++ 11以降のバリアントに変更する必要があります。
[元の回答が続きます]
試してみてください:
#define jack_VS queen
#define queen_VS jack
#define USER jack // jack or queen, your choice
#define USER_VS USER##_VS // jack_VS or queen_VS
// stringify usage: S(USER) or S(USER_VS) when you need the string form.
#define S(U) S_(U)
#define S_(U) #U
更新:ANSIトークンの貼り付けがわかりにくい場合があります。;-D
#
マクロの前にシングルを置くと、マクロは裸の値ではなく、その値の文字列に変更されます。
##
2つのトークンの間にdoubleを入れると、それらは1つのトークンに連結されます。
したがって、マクロにUSER_VS
は、設定方法に応じて、展開jack_VS
またはqueen_VS
がありますUSER
。
文字列化マクロは、S(...)
名前のマクロの値を文字列に変換されるように、マクロ間接を使用しています。マクロの名前の代わりに。
したがって、設定方法に応じて、(または)にUSER##_VS
なります。jack_VS
queen_VS
USER
後で、stringifyマクロが(この例では)のS(USER_VS)
値として使用されると、その値()を文字列に変換する間接ステップに渡されます。USER_VS
jack_VS
S_(jack_VS)
queen
"queen"
に設定USER
するqueen
と、最終結果は文字列になります"jack"
。
トークンの連結については、https://gcc.gnu.org/onlinedocs/cpp/Concatenation.htmlを参照してください。
トークン文字列の変換については、https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringificationを参照してください。
[タイプミスを修正するために2015.02.15を更新しました。]
#if 0 == c_strcmp( USER, JACK )
たconstexpr int comp1 = c_strcmp( USER, JACK );
#if 0 == comp1
#if
この例は、USERがJACKであるためにのみ機能します。USERがQUEENだった場合、それが言うUSER IS QUEEN
とUSER_VS IS QUEEN
constexpr
プリプロセッサディレクティブから関数を呼び出すことはできません(でも)。
以下はclangで私のために働いた。シンボリックマクロ値の比較として表示されるものを許可します。#error xxxは、コンパイラが実際に何をするかを確認するためのものです。catの定義を#definecat(a、b)a ## bに置き換えると、問題が発生します。
#define cat(a,...) cat_impl(a, __VA_ARGS__)
#define cat_impl(a,...) a ## __VA_ARGS__
#define xUSER_jack 0
#define xUSER_queen 1
#define USER_VAL cat(xUSER_,USER)
#define USER jack // jack or queen
#if USER_VAL==xUSER_jack
#error USER=jack
#define USER_VS "queen"
#elif USER_VAL==xUSER_queen
#error USER=queen
#define USER_VS "jack"
#endif
すでに上で述べたように、ISO-C11プリプロセッサは文字列比較をサポートしていません。ただし、「反対の値」でマクロを割り当てる問題は、「トークンの貼り付け」と「テーブルアクセス」で解決できます。Jesseの単純な連結/文字列化マクロソリューションは、連結の評価(ISO C11に準拠)の前に文字列化が行われるため、gcc5.4.0では失敗します。ただし、修正することができます。
#define P_(user) user ## _VS
#define VS(user) P_ (user)
#define S(U) S_(U)
#define S_(U) #U
#define jack_VS queen
#define queen_VS jack
S (VS (jack))
S (jack)
S (VS (queen))
S (queen)
#define USER jack // jack or queen, your choice
#define USER_VS USER##_VS // jack_VS or queen_VS
S (USER)
S (USER_VS)
最初の行(macro P_()
)は1つの間接参照を追加して、次の行(macro VS()
)が文字列化の前に連結を終了できるようにします(マクロに2層の間接参照が必要な理由を参照 )。文字列化マクロ(S()
およびS_()
)はJesseからのものです。
OPのif-then-else構造よりも保守がはるかに簡単なテーブル(マクロjack_VS
とqueen_VS
)は、Jesseによるものです。
最後に、次の4行のブロックが関数スタイルのマクロを呼び出します。最後の4行のブロックは、ジェシーの答えからのものです。
コードを格納しfoo.c
てプリプロセッサを呼び出すと、次のようになりgcc -nostdinc -E foo.c
ます。
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "foo.c"
# 9 "foo.c"
"queen"
"jack"
"jack"
"queen"
"jack"
"USER_VS"
出力は期待どおりです。最後の行は、文字列化の前にUSER_VS
マクロが展開されていないことを示しています。
#if (S(USER)=="jack")
-使用しているとき、私はプリプロセッサのエラーを取得します"
- error: invalid token at start of a preprocessor expression
。
文字列が(あなたの場合のように)コンパイル時定数である場合、次のトリックを使用できます。
#define USER_JACK strcmp(USER, "jack")
#define USER_QUEEN strcmp(USER, "queen")
#if $USER_JACK == 0
#define USER_VS USER_QUEEN
#elif USER_QUEEN == 0
#define USER_VS USER_JACK
#endif
コンパイラーは事前にstrcmpの結果を通知し、strcmpをその結果に置き換えるため、プリプロセッサー・ディレクティブと比較できる#defineが得られます。コンパイラー間に差異があるかどうか/コンパイラー・オプションへの依存性があるかどうかはわかりませんが、GCC4.7.2では機能しました。
編集:さらに調査すると、これはツールチェーン拡張であり、GCC拡張ではないように見えるので、それを考慮に入れてください...
$
プリプロセッサ拡張のいくつかの種類は?
answereパトリックとによってジェシー・チザムは、私は次の操作を行い作っ:
#define QUEEN 'Q'
#define JACK 'J'
#define CHECK_QUEEN(s) (s==QUEEN)
#define CHECK_JACK(s) (s==JACK)
#define USER 'Q'
[... later on in code ...]
#if CHECK_QUEEN(USER)
compile_queen_func();
#elif CHECK_JACK(USER)
compile_jack_func();
#elif
#error "unknown user"
#endif
の代わりに #define USER 'Q'
#define USER QUEEN
動作するはずですが、テストされていません また、機能し、扱いやすいかもしれません。
編集:@Jean-FrançoisFabreのコメントによると、私は自分の答えを適応させました。
(s==QUEEN?1:0)
することにより(s==QUEEN)
、あなたは結果がすでにブールで、三元を必要としない
#define USER_IS(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9)\
ch0==c0 && ch1==c1 && ch2==c2 && ch3==c3 && ch4==c4 && ch5==c5 && ch6==c6 && ch7==c7 ;
#define ch0 'j'
#define ch1 'a'
#define ch2 'c'
#define ch3 'k'
#if USER_IS('j','a','c','k',0,0,0,0)
#define USER_VS "queen"
#elif USER_IS('q','u','e','e','n',0,0,0)
#define USER_VS "jack"
#endif
基本的には、自動的に初期化された可変長の静的char配列ではなく、手動で初期化された固定長の静的char配列で、常に終了するnull文字で終了します。
USERが引用符で囲まれた文字列として定義されている場合は、これを行うことはできません。
ただし、USERがJACK、QUEEN、Jokerなどの場合は、これを行うことができます。
使用する2つのトリックがあります:
#define JACK
、何かをしなくてもJACKと比較できます。それでは、まず始めましょう:
#define JACK_QUEEN_OTHER(u) EXPANSION1(ReSeRvEd_, u, 1, 2, 3)
さて、私が書いたJACK_QUEEN_OTHER(USER)
場合、USERがJACKの場合、プリプロセッサはそれを次のように変換します。EXPANSION1(ReSeRvEd_, JACK, 1, 2, 3)
ステップ2は連結です:
#define EXPANSION1(a, b, c, d, e) EXPANSION2(a##b, c, d, e)
今にJACK_QUEEN_OTHER(USER)
なるEXPANSION2(ReSeRvEd_JACK, 1, 2, 3)
これにより、文字列が一致するかどうかに応じて、いくつかのコンマを追加する機会が与えられます。
#define ReSeRvEd_JACK x,x,x
#define ReSeRvEd_QUEEN x,x
USERがJACKであれば、JACK_QUEEN_OTHER(USER)
となりEXPANSION2(x,x,x, 1, 2, 3)
USERはQUEENの場合、JACK_QUEEN_OTHER(USER)
となりEXPANSION2(x,x, 1, 2, 3)
ユーザーが他の場合には、JACK_QUEEN_OTHER(USER)
なりEXPANSION2(ReSeRvEd_other, 1, 2, 3)
この時点で、重大な問題が発生しました。EXPANSION2マクロの4番目の引数は、渡された元の引数がジャック、クイーン、またはその他のものであるかどうかに応じて、1、2、または3のいずれかです。だから私たちがしなければならないのはそれを選ぶことだけです。長い理由から、最後のステップには2つのマクロが必要です。不要に思えますが、EXPANSION2とEXPANSION3になります。
すべてをまとめると、次の6つのマクロがあります。
#define JACK_QUEEN_OTHER(u) EXPANSION1(ReSeRvEd_, u, 1, 2, 3)
#define EXPANSION1(a, b, c, d, e) EXPANSION2(a##b, c, d, e)
#define EXPANSION2(a, b, c, d, ...) EXPANSION3(a, b, c, d)
#define EXPANSION3(a, b, c, d, ...) d
#define ReSeRvEd_JACK x,x,x
#define ReSeRvEd_QUEEN x,x
そして、あなたはこれらをこのように使うかもしれません:
int main() {
#if JACK_QUEEN_OTHER(USER) == 1
printf("Hello, Jack!\n");
#endif
#if JACK_QUEEN_OTHER(USER) == 2
printf("Hello, Queen!\n");
#endif
#if JACK_QUEEN_OTHER(USER) == 3
printf("Hello, who are you?\n");
#endif
}
必須のゴッドボルトリンク:https://godbolt.org/z/8WGa19