私は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コードを使用することもできます。
[更新:2018.05.03]
[〜#〜] caveat [〜#〜]:すべてのコンパイラが同じ方法でC++ 11仕様を実装しているわけではありません。以下のコードは、私がテストしたコンパイラで動作しますが、多くのコメント作成者は異なるコンパイラを使用しました。
Shafik Yaghmourの答えから引用: コンパイル時にC文字列の長さを計算します。これは本当にconstexprですか?
定数式はコンパイル時に評価されることを保証されていません。C++標準のドラフトセクション5.19からこれを言っている定数式以外の引用だけがあります。
[...]> [注:定数式は翻訳中に評価できます。
そのWord can
は世界のすべての違いを生みます。
そのため、コンパイラ作成者の仕様の解釈に応じて、constexpr
を含むこの(または任意の)回答のYMMVを使用します。
[2016.01.31更新]
文字列の比較を必要とせずに目標を達成することでOPの_compile time string compare
_アスペクト全体をavoidedしたため、一部の人は私の以前の答えを好まなかったので、詳細な答え。
できません! 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
_
したがって、最終的には、USER
および_USER_VS
_の最終的な文字列値を選択するという目標を達成する方法を変更する必要があります。
C99ではコンパイル時の文字列比較はできませんが、コンパイル時の文字列の選択はできます。
コンパイル時のスティング比較を本当に行う必要がある場合は、その機能を許可する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つのトークンの間に二重の_##
_を挿入すると、それらは単一のトークンに連結されます。
したがって、マクロ_USER_VS
_には、USER
の設定方法に応じて、_jack_VS
_または_queen_VS
_という展開があります。
stringifyマクロS(...)
はマクロ間接指定を使用するため、名前付きマクロの値は文字列に変換されます。マクロの名前の代わりに。
したがって、USER
の設定方法に応じて、_USER##_VS
_は_jack_VS
_(または_queen_VS
_)になります。
後で、stringifyマクロがS(USER_VS)
として使用されると、_USER_VS
_(この例では_jack_VS
_)の値が値(queen
)を文字列_"queen"
_に変換する間接ステップS_(jack_VS)
。
USER
をqueen
に設定すると、最終結果は文字列_"jack"
_になります。
トークンの連結については、以下を参照してください: https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
トークン文字列の変換については、以下を参照してください: https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
[タイプミスを修正するために2015.02.15を更新しました。]
文字列の代わりに数値を使用します。
最後に、定数JACKまたはQUEENを文字列に変換するには、stringize(および/またはtokenize)演算子を使用します。
以下はclangでうまくいきました。シンボリックマクロ値の比較として表示されるものを許可します。 #エラーxxx コンパイラが実際に行うことを確認するだけです。交換 ネコ 定義 #define cat(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プリプロセッサはnot文字列比較をサポートします。ただし、マクロに「反対の値」を割り当てる問題は、「トークンの貼り付け」と「テーブルへのアクセス」で解決できます。 Jesseの単純な連結/文字列化マクロソリューションは、gcc 5.4.0で失敗します。これは、文字列化が行われるためですbefore連結の評価(ISO C11に準拠)。ただし、修正することができます。
_#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_()
)は、次の行(macro VS()
)が連結を終了できるように1つの間接参照を追加しますbefore文字列化( を参照)マクロに二重層の間接参照が必要なのはなぜですか? )。文字列化マクロ(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
_マクロが文字列化の前にnot展開されていることを示しています。
Patrick と Jesse Chisholm による回答者は、私に次のことをさせました。
#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のコメントによると、私は答えを修正しました。
文字列がコンパイル時定数である場合(あなたの場合)、次のトリックを使用できます。
#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を提供します。コンパイラとコンパイラオプションの依存関係に違いがあるかどうかはわかりませんが、GCC 4.7.2ではうまくいきました。
編集:さらに調査すると、これはGCC拡張機能ではなくツールチェーン拡張機能であるように見えるので、考慮に入れてください...
#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
基本的に、常に終了するnull文字で自動的に初期化される可変長の静的char配列の代わりに、手動で初期化される固定長の静的char配列