33

代替タイトル(検索を支援するため)

  • プリプロセッサトークンを文字列に変換します
  • Cマクロの値からchar文字列を作成するにはどうすればよいですか?

元の質問

コンパイル時にC を使用してリテラル文字列を作成したいと思います。#define

文字列は、デバッグ、リリースなどのために変更されるドメインです。

私はこのようなことをしたいと思います:

#ifdef __TESTING
    #define IV_DOMAIN domain.org            //in house testing
#elif __LIVE_TESTING
    #define IV_DOMAIN test.domain.com       //live testing servers
#else
    #define IV_DOMAIN domain.com            //production
#endif

// Sub-Domain
#define IV_SECURE "secure.IV_DOMAIN"             //secure.domain.org etc
#define IV_MOBILE "m.IV_DOMAIN"

しかし、プリプロセッサは「」内の何も評価しません

  1. これを回避する方法はありますか?
  2. これもいい考えですか?
4

7 に答える 7

40

C では、文字列リテラルは自動的に連結されます。例えば、

const char * s1 = "foo" "bar";
const char * s2 = "foobar";

s1s2は同じ文字列です。

したがって、あなたの問題に対する答え(トークンの貼り付けなし)は

#ifdef __TESTING
    #define IV_DOMAIN "domain.org"
#elif __LIVE_TESTING
    #define IV_DOMAIN "test.domain.com"
#else
    #define IV_DOMAIN "domain.com"
#endif

#define IV_SECURE "secure." IV_DOMAIN
#define IV_MOBILE "m." IV_DOMAIN
于 2009-04-28T14:30:22.230 に答える
32

これを行うには、いくつかの方法があります。

  1. 文字列リテラルのみを扱っている場合は、単純に文字列を使用するだけです。文字列リテラルを次々に配置すると、コンパイラはそれらを連結します。

  2. 文字列リテラル以外のものが関係している可能性がある場合 (つまり、マクロから新しい識別子を作成している場合)、' ##" プリプロセッサ トークンの貼り付け演算子を使用し#ます。マクロを作成するには、' ' ' 文字列化演算子も使用する必要があるでしょう。リテラル文字列に。

#1の例:

#ifdef __TESTING
    #define IV_DOMAIN "domain.org"                        //in house testing
#elif __LIVE_TESTING
    #define IV_DOMAIN "test.domain.com"           //live testing servers
#else
    #define IV_DOMAIN "domain.com"                        //production
#endif

// Sub-Domain
#define IV_SECURE "secure." IV_DOMAIN          //secure.domain.org etc
#define IV_MOBILE "m." IV_DOMAIN

そして、トークン貼り付け演算子に関する限り、トークン貼り付けプリプロセッサ演算子の使用を提案した回答のほとんどが実際に試したとは思いません-使用するのは難しい場合があります。

IV_SECUREよく提案される回答を使用すると、マクロを使用しようとしたときにコンパイラ エラーが発生します。理由は次のとおりです。

#define IV_SECURE "secure."##IV_DOMAIN

次のように展開されます。

"secure"domain.org

'#`' 'stringizing' 演算子を使用してみてください:

#define IV_SECURE "secure." #IV_DOMAIN

しかし、古いマクロだけでなく、マクロ引数でのみ機能するため、それは機能しません。

トークンの貼り付け ('##') または文字列化 ('#') の前処理演算子を使用する場合に注意すべきことの 1 つは、それらがすべての場合に適切に機能するために、余分なレベルの間接化を使用する必要があることです。

これを行わず、トークン貼り付け演算子に渡されたアイテムがマクロ自体である場合、おそらく望んでいない結果が得られます。

#include <stdio.h>

#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)

#define BAD_PASTE(x,y) x##y
#define BAD_STRINGIFY(x) #x

#define SOME_MACRO function_name

int main() 
{
    printf( "buggy results:\n");
    printf( "%s\n", STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
    printf( "%s\n", BAD_STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
    printf( "%s\n", BAD_STRINGIFY( PASTE( SOME_MACRO, __LINE__)));

    printf( "\n" "desired result:\n");
    printf( "%s\n", STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
}

出力:

buggy results:
SOME_MACRO__LINE__
BAD_PASTE( SOME_MACRO, __LINE__)
PASTE( SOME_MACRO, __LINE__)

desired result:
function_name21

したがって、元のIV_DOMAIN定義と上記のユーティリティ マクロを使用すると、これを実行して必要なものを取得できます。

// Sub-Domain
#define IV_SECURE "secure." STRINGIFY( IV_DOMAIN)   //secure.domain.org etc
#define IV_MOBILE "m." STRINGIFY( IV_DOMAIN)
于 2009-04-28T14:38:27.453 に答える
8

次に一緒にある文字列は、Cコンパイラによって結合されます。

#define DOMAIN "example.com"
#define SUBDOMAIN "test." DOMAIN
const char *asCString = SUBDOMAIN;
NSString *asNSString = @SUBDOMAIN;
于 2009-04-28T14:25:41.367 に答える
8

あなたの最初の質問には多くの適切で正しい答えがありますが、あなたの 2 番目の質問には答えがありません。サーバー名を変更するためだけにソフトウェア (特にリリース バージョン) を再構築する必要があるのはなぜですか? また、ソフトウェアのどのバージョンがどのサーバーを指しているのか、どうすればわかりますか? 実行時にチェックするメカニズムを組み込む必要があります。お使いのプラットフォームで実用的な場合は、構成ファイルからドメイン/URL をロードすることをお勧めします。その目的のために「実用的」ではないのは、最小の組み込みプラットフォームだけです:)

于 2009-04-28T14:40:04.033 に答える
6

##演算子を使用してみてください

#define IV_SECURE secure.##IV_DOMAIN
于 2009-04-28T14:23:26.803 に答える
5

必要なのは、# 演算子と ## 演算子、および自動文字列連結です。

# 前処理演算子は、マクロ パラメーターを文字列に変換します。## 演算子は、2 つのトークン (マクロ パラメーターなど) を一緒に貼り付けます。

私が思いつく可能性は、

#define IV_DOMAIN domain.org
#define IV_SECURE(DOMAIN) "secure." #DOMAIN

IV_SECUREをに変更する必要があります

#define IV_SECURE "secure." "domain.org"

これは自動的に "secure.domain.org" に連結されます (変換のフェーズが C と C++ で同じであると仮定します)。

別の編集:コメントを読んでください。私がどのように混乱したかを示しています。私は C の経験が豊富であることを覚えておいてください。この回答は削除しますが、C プリプロセッサによって混乱しやすい例として残しておくことにしました。

于 2009-04-28T14:29:36.630 に答える
3

他の人が指摘したように、トークンの貼り付けを使用してください。また、次のようなマクロ名にも注意する必要があります。

__TESTING

実装のためにCで予約されています(Objective Cについては知りません)-独自のコードでそれらを使用することは許可されていません。予約済みの名前は、2 つのアンダースコアを含むもの、およびアンダースコアと大文字で始まるものです。

于 2009-04-28T14:30:26.007 に答える