C++プリプロセッサディレクティブを使用して、プリプロセッサシンボルが定義されているが値がないかどうかをテストできますか?そんな感じ:
_#define MYVARIABLE
#if !defined(MYVARIABLE) || #MYVARIABLE == ""
... blablabla ...
#endif
_
編集:これを実行している理由は、現在取り組んでいるプロジェクトは/DMYSTR=$(MYENVSTR)
を介して環境から文字列を取得することになっており、この文字列が空である可能性があるためです。ユーザーがこの文字列を定義し忘れた場合、プロジェクトがコンパイルに失敗することを確認したいと思います。
相馬マクロマジック:
#define DO_EXPAND(VAL) VAL ## 1
#define EXPAND(VAL) DO_EXPAND(VAL)
#if !defined(MYVARIABLE) || (EXPAND(MYVARIABLE) == 1)
Only here if MYVARIABLE is not defined
OR MYVARIABLE is the empty string
#endif
コマンドラインでMYVARIABLEを定義する場合、デフォルト値は1です。
g++ -DMYVARIABLE <file>
ここで、MYVARIABLEの値は1です。
g++ -DMYVARIABLE= <file>
ここで、MYVARIABLEの値は空の文字列です
#define DO_QUOTE(X) #X
#define QUOTE(X) DO_QUOTE(X)
#define MY_QUOTED_VAR QUOTE(MYVARIABLE)
std::string x = MY_QUOTED_VAR;
std::string p = QUOTE(MYVARIABLE);
この問題の解決策を見たことがありませんが、一般的に使用されていないことに驚いています。 Xcode Objcで動作するようです。 「値なしで定義」と「定義セット0」を区別する
#define TRACE
#if defined(TRACE) && (7-TRACE-7 == 14)
#error TRACE is defined with no value
#endif
ユーザーがこの文字列を定義し忘れた場合、プロジェクトがコンパイルに失敗することを確認したいと思います。
前のビルドステップでこれをチェックしますが、コンパイル時にこれを行うことができます。簡潔にするためにBoostを使用する:
#define A "a"
#define B
BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(A)) > 1); // succeeds
BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(B)) > 1); // fails
Mehradの答えは、それを機能させるために拡張する必要があります。彼のコメントも
/ * MYVARI(A)BLEはここでは未定義です* /
不正解です。未定義の変数をテストするには、単純なテスト_#ifndef MYVARIABLE
_があります。
しかし、そのようなテストの後、彼の表現は元の質問の正しい解決につながります。マクロMYVARIABLEの未定義、定義済みだが空、および空ではない値に対して、このコードが機能することをテストしました。
_#ifndef MYVARIABLE
/* MYVARIABLE is undefined here */
#Elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIABLE is defined with no value here */
#else
/* MYVARIABLE is defined here */
#endif
_
_#Elif
_ステートメント~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
は次のように機能します。
MYVARIABLE
が定義されているが空の場合、~(~+0) == 0 && ~(~+1) == 1
に展開され、_0==0 && 1==1
_になります(二重否定~~はID演算子です)。MYVARIABLE
が数値(nなど)に定義されている場合、~(~n+0)==0 && ~(~n+1)==1
に展開されます。 _&&
_の左側では、式~(~n+0)==0
は_n==0
_に評価されます。しかし、_n==0
_の場合、右側は~(~0+1)==1
に評価され、〜0は-1から~(-1+1)==1
になり、次に_~0==1
_、最後に_-1==1
_になります。 、これは明らかに誤りです。MYVARIABLE
が数値以外の値に定義されている場合、プリコンパイラーはすべての不明なシンボルを0に減らし、n == 0の前のケースをもう一度取得します。私の完全なテストコード(test.cファイルとして保存):
_#include <stdio.h>
int main() {
printf("MYVARIABLE is "
#ifndef MYVARIABLE
"undefined"
#Elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
"defined without a value"
#else
"defined with this value : %i", MYVARIABLE
#endif
);
printf("\n");
}
_
GNUプリプロセッサcppを使用すると、どのコードが生成されるかを実験して確認できます。
_# undefined
cpp test.c
#defined without a value
cpp -DMYVARIABLE= test.c
#defined wit an implicit value 1
cpp -DMYVARIABLE test.c
#defined wit an explicit value 1
cpp -DMYVARIABLE=1 test.c
#defined wit an explicit value a
cpp -DMYVARIABLE=a test.c
_
またはコンパイルと実行の出力(一部のLinuxの場合)
_$ gcc -o test test.c ; ./test
MYVARIABLE is undefined
$ gcc -DMYVARIABLE= -o test test.c ; ./test
MYVARIABLE is defined without a value
$ gcc -DMYVARIABLE -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=1 -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=a -o test test.c ; ./test
test.c: In function ‘main’:
<command-line>:0:12: error: ‘a’ undeclared (first use in this function)
...
_
MYVARIABLEが 'a'として定義されている最後の実行では、エラーはマクロ定義のエラーではありません。マクロは、「この値で定義された...」という最後のケースを正しく導きます。しかし、この値は「a」であり、「a」はコードで定義されていないため、コンパイラまたはコースはこれを通知する必要があります。
このように、最後のケースは、元の質問の意図が非常に危険である理由の非常に良い例です。マクロを使用して、ユーザーはコンパイルするコードにプログラム行のシーケンスを導入できます。このようなコードが導入されていないことを確認するには、有効な値でマクロをさらに多く確認する必要があります。このタスクを前処理に任せる代わりに、おそらく完全なスクリプトが必要です。そしてその場合、前処理でそれをチェックすることの用途は何ですか?
BOOST_PP_IS_EMPTY
マクロは次のようになります:
#include <boost/preprocessor/facilities/is_empty.hpp>
#define MYVARIABLE
#if !defined(MYVARIABLE) || !BOOST_PP_IS_EMPTY(MYVARIABLE)
// ... blablabla ...
#endif
それは私にとってはトリックでした。このマクロは文書化されていないので、追加するつもりですので、注意して使用してください。
これができるとは思いません。そうは言っても、私はそれの必要性を見ていない。プリプロセッサ#define
シンボルを作成するときは、#if
で使用するために1または0として定義するか、空白のままにする規則を確立する必要があります。
プリプロセッサは数値のみをチェックできるため、これはできません。文字列比較はプリプロセッサ構文ではカバーされていません。
#if MYVARIABLE==0
私の答えは少なくとも30文字でなければならないので、それで十分です!
追加のマクロなしでハックを使用できます:
#if ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIBLE is undefined here */
#endif