2016-05-03 9 views
2

Cプリプロセッサを使用して、パラメータタイプのみが変更される関数ファミリを定義したいとします。Cプリプロセッサマクロの拡張連結

#include <stdint.h> 
#include <stdio.h> 

#define type_vector(t)            \ 
t * t##vector(int32_t nl, int32_t nh)        \ 
{                 \ 
    t * v = NULL; /* malloc(...) */         \ 
    return v;              \ 
} 

type_vector(int8_t) 
type_vector(int32_t) 
type_vector(int64_t) 

int main() { 
    int32_t * p; 
    p = int32_tvector(10, 12); 
    return 0; 
} 

これはうまくいきます。

ここで、関数名にint8_tの代わりにi8、int32_tの代わりにi32などの短い型名を使用したいとします。 マクロ関数宣言に2番目のパラメータを追加したくない代わりに、 "短い"型名の単一の定義を持つ。 基本的に、私が書いた最初のものだった:

#define sn_int8_t i8 
#define sn_int32_t i32 
#define sn_int64_t i64 

#define sn(t)   sn_##t 

#define type_vector(t)            \ 
t * sn(t)##vector(int32_t nl, int32_t nh)       \ 
{                 \ 
    t * v = NULL; /* malloc(...) */         \ 
    return v;              \ 
} 

type_vector(int8_t) 
type_vector(int32_t) 
type_vector(int64_t) 

int main() { 
    int32_t * p; 
    p = i32vector(10, 12); 
    return 0; 
} 

しかし、これは、コンパイルされません、次のエラーを与える:私の知る限り理解されるように

error: pasting ")" and "vector" does not give a valid preprocessing token 
t * sn(t)##vector(int32_t nl, int32_t nh)       \ 

を、問題が「あるためです) "と"# "を並べて表示します。 だから私は次のようでした:

#define sn_int8_t(f) i8##f 
#define sn_int32_t(f) i32##f 
#define sn_int64_t(f) i64##f 

#define sn2(t,f)  sn_##t(f) 

#define type_vector(t)            \ 
t * sn2(t,vector)(int32_t nl, int32_t nh)       \ 
{                 \ 
    t * v = NULL; /* malloc(...) */         \ 
    return v;              \ 
} 

type_vector(int8_t) 
type_vector(int32_t) 
type_vector(int64_t) 

int main() { 
    int32_t * p; 
    p = i32vector(10, 12); 
    return 0; 
} 

そして、これが再び正常に動作します。今

、私は例えば、関数名に接頭辞を追加したいと仮定"remote_"。 SN2が展開されていないよう

は単に

#define type_vector(t)            \ 
t * remote_##sn2(t,vector)(int32_t nl, int32_t nh)     \ 
{                 \ 
    t * v = NULL; /* malloc(...) */         \ 
    return v;              \ 
} 

を置くことは、動作しません。だから私はこれを試してみました:

int32_t * remote_sn2(int32_t,vector) 

それを行うにはどのような方法があります:

#include <stdint.h> 
#include <stdio.h> 

#define sn_int8_t(f) i8##f 
#define sn_int32_t(f) i32##f 
#define sn_int64_t(f) i64##f 

#define sn2(t,f)  sn_##t(f) 

#define short_name(n,t,f) n##_##sn2(t,f) 

#define remote_type_vector(t)          \ 
t * short_name(remote,t,vector)(int32_t nl, int32_t nh)    \ 
{                 \ 
    t * v = NULL;             \ 
    return v;              \ 
} 

remote_type_vector(int8_t) 
remote_type_vector(int32_t) 
remote_type_vector(int64_t) 

int main() { 
    int32_t * p; 
    p = remote_i32vector(10, 12); 
    return 0; 
} 

基本的に、これはマクロSN2が展開されていないので、私のような宣言を与えることが動作しませんか?

注:私はC++テンプレートを使用したくありません。

+1

一部の人々は魔法のこの種を主張しているが悪である... _flexible配列member_を使用 –

+0

は、はるかに簡単思うになるだろう。残りについて:TL; DR。 [mcve]を提供してください。 – Olaf

+0

"マクロ関数宣言に第2パラメータを追加したくありません" - どうしてですか?非常に頻繁にマクロを呼び出すのではありません。 2番目のパラメータは、 'typedef'なしで複合名(' char * '、' struct thing')を持つ型を使うこともできます。 –

答えて

0

ここにあなたのニーズのすべてのために働くべきで統一されたソリューションです:

#define sn_int8_t(p,s) p##i8##s 
#define sn_int32_t(p,s) p##i32##s 
#define sn_int64_t(p,s) p##i64##s 

#define sn2(t,p,s)  sn_##t(p,s) 

#define type_vector(t)            \ 
t * sn2(t,,vector)(int32_t nl, int32_t nh)       \ 
{                 \ 
    t * v = NULL; /* malloc(...) */         \ 
    return v;              \ 
} 

#define remote_type_vector(t)          \ 
t * sn2(t,remote,vector)(int32_t nl, int32_t nh)     \ 
{                 \ 
    t * v = NULL;             \ 
    return v;              \ 
} 

type_vector(int8_t) 
type_vector(int32_t) 
type_vector(int64_t) 

remote_type_vector(int8_t) 
remote_type_vector(int32_t) 
remote_type_vector(int64_t)