2017-01-17 21 views
9

連結プリプロセッサ演算子##を使用してcのマクロを理解しようとしましたが、トークンに問題があることに気付きました。私はそれが簡単だと思ったが、実際にはそうではない。マクロ連結内の有効なプリプロセッサトークン

連結は、2つのトークンを連結して新しいトークンを作成するためのものです。 例:私はそれを私は常に例えばpasting both argument does not give a valid preprocessor token.

1aafoo(1,aa)結果を連結する理由というエラーを取得いくつかの引数を与えたときに()またはint*

を連結私は(

#define foo(x,y) x ## y 
foo(x,y) 

を試してみましたトークンの種類は?それはなぜ有効なのですか)、foo(int,*)私はエラーが発生しました。

どのトークンが有効であるかを知る方法はありますか、それが私の心の中でどのように明確にできるかを理解するには良いリンクを張ることが可能ですか? (私はすでにグーグルでgoogled)

私は何が欠けていますか?

私は感謝します。

+3

リンクを要求するのはトピック外です。そして、あなたが実際にそのエラーを引き起こすために渡したものを実際に示しているなら、あなたは助けを受けることができます。 – StoryTeller

+0

私は '1aa'は有効な前処理トークンではないと思っています –

+0

6つのトークンタイプには属しませんが、gccはそれについては何も警告しません。 – Sabrina

答えて

5

プリプロセッサトークン連結が新しいトークンを生成するためのものであるが、任意の言語が一緒に構築貼付することができない(例えば、付与、gcc documentation):

しかし、一緒にない2つのトークンが形成有効なトークンを貼り付けた にすることはできません。たとえば、 のxを+と連結することはできません。

int*は、2つのトークンではなく、一つであるように

#define MAKEPTR(NAME) NAME ## * 
MAKEPTR(int) myIntPtr; 

のようなタイプの外にポインタを作るマクロの試みは、無効です。

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

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

利回り:

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

トークンquit_commandは、以前に存在しなかったが、トークンを連結して生成された

上記のリンクの例は、しかし、新しいトークンの生成を示しています。

#define MAKEPTR(TYPE) TYPE* 
MAKEPTR(int) myIntPtr; 

が実際に有効であり、フォームのマクロTYPEからポインタ型を生成

注、例えばint*のうち、intです。

+0

したがって、連結は新しい既存のトークンを作成するために2つのトークンを取りますか? – Sabrina

+0

トークンまたはマクロパラメータ... –

+0

私はすでにこの例を知っています。 – Sabrina

2

前処理トークンは、C言語の文法によって定義されます(第6章を参照)。現在の標準の4:

preprocessing-token: 
        header-name 
        identifier 
        pp-number 
        character-constant 
        string-literal 
        punctuator 
        each non-white-space character that cannot be one of the above 

は、これらの用語のそれぞれの意味は、他の場所文法で定義されています。ほとんどは自明である。 identifierは、有効な変数名(またはキーワードでない場合)を意味し、pp-numberは整数と浮動小数点定数を含みます。

標準Cでは、2つの前処理トークンを貼り付けた結果が別の有効な前処理トークンでなければなりません。歴史的には、いくつかのプリプロセッサでは貼り付けができませんでしたが、貼り付けをしないのと同じですが、別のコンパイラでコードをコンパイルすると混乱することになります。

+0

「1aaa」はどうですか? – Sabrina

+0

'##'を使うことはお勧めしません。 – Sabrina

+0

-1が整数なので、なぜfoo( - 、1)が失敗するのか分かりません。 –

2

混乱の原因と思われるので、1aaという文字列は有効なプリプロセッサトークンです。それが定義され(§現在のC規格の6.4.8)pp-numberのインスタンスである:すなわち

 pp-number: 
      digit 
      . digit 
      pp-number  digit 
      pp-number  identifier-nondigit 
      pp-number  e sign 
      pp-number  E sign 
      pp-number  p sign 
      pp-number  P sign 
      pp-number  . 

、数字またはpp-number開始します。の後ろに桁が続き、その後に「識別子非桁」(つまり、文字、下線など識別子の一部となりうる他のもの)の文字列、またはeまたはpの任意の文字列を含めることができます(大文字または小文字のいずれか)、プラス記号またはマイナス記号が続きます。

つまり、0x1e+2は有効なpp-numberであり、0x1f+1は有効ではありません(3つのトークンです)。有効なプログラムでは、前処理フェーズで存続するすべてのpp-numberは、数値定数表現の構文を満たす必要があります。つまり、テキスト0x1e+2を含むプログラムは無効と見なされます。道徳的なものがあれば、空白を寛大に使うべきだということです。それは費用がありません。

pp-numberの意図は、最終的にCのいくつかの将来のバージョンで番号(数字は、27LUようなタイプと符合を示すアルファベット接尾辞、続くことができることに注意してください)であるかもしれないすべてのものを含めることです。

ただし、int*は有効なプリプロセッサトークンではありません。これは2つのトークン(-3)であるため、トークン連結演算子では形成できません。

..は有効なトークンではないため、トークンペーストルールのもう1つの奇妙な結果は、トークン連結を使用して有効なトークン...を生成することができないことです。 (a##b##cは何らかの順序で評価されなければならないので、3つのプリプロセッサマクロがすべてに展開されても、Visual Studioがそれを受け入れるとは思うが、必ずコンパイラに失敗する..トークンを作成しようとする必要がある)

最後に、コメント記号/*//ではなく、トークンです。プログラムテキストをトークンに分割する前に、コメントは空白に置き換えられます。したがって、トークンペーストを使ってコメントを作成することはできません(少なくとも、準拠しているコンパイラではない)。

関連する問題