2011-01-17 18 views
2

#defineマクロへの型検査が可能ですか?例:Cでのマクロ引数の型チェックの確認

typedef enum 
{ 
    REG16_A, 
    REG16_B, 
    REG16_C 
}REG16; 

#define read_16(reg16) read_register_16u(reg16); \ 
         assert(typeof(reg16)==typeof(REG16)); 

上記のコードは動作していないようです。私は間違って何をしていますか?

私はgccを使用しています。私はこのプロジェクトで常にgccを使用することを保証できます。コードは移植可能である必要はありません。

+0

私が知っている限り、Cは型に関する情報を格納していないので、実行時には取得できません。 – Marii

答えて

3

いいえ、マクロではタイプチェックを行うことはできません。しかし、結局のところ、なぜマクロですか? staticinline関数を書くことができます(これはおそらく)コンパイラによってインライン化されます。ここではに型チェックを行います。

static inline void read_16(REG16 reg16) { 
    read_register_16u(reg16); 
} 
+0

いいえ、これはタイプ・チェックもしません。警告でもありません。私は別の方法を試しているからです。私の他の質問を参照してください:http://stackoverflow.com/questions/4669454/how-to-make-gcc-warn-about-passing-wrong-enum-to-a-function – Rocketmagnet

+0

これは*エラーチェック、私の参照してください他の質問に答えてください。 – ulidtko

+0

C++でのエラーチェックのみです。これはC. – Rocketmagnet

1

、ulidtkoのアイデアを継続inline機能を取ると、それが何かを返しました:あなたは、時間のアサーションをコンパイル行うことができますものなどで

inline 
bool isREG16(REG16 x) { 
    return true; 
} 

を:

typedef char testit[sizeof(isREG16(yourVariable))]; 
1

ありませんCのマクロは本質的に型が危険であり、C言語の型をチェックしようとすると問題が発生します。

最初に、マクロは、タイプ情報が利用できないコンパイル段階のテキスト置換によって展開されます。そのため、マクロ展開時に引数の型をコンパイラが確認することは全く不可能です。

あなたが問題になっているassertのように、拡張されたコードのチェックを実行しようとすると、第二に、あなたのチェックは実行時まで延期されており、また、列挙子ので

a = read_16(REG16_A); 

のような一見無害な構造を上のトリガされます(REG16_A,REG16_BおよびREG16_C)はタイプintであり、種類はREG16ではありません。

タイプセーフティを使用する場合は、関数を使用することをお勧めします。コンパイラがそれをサポートしている場合は、関数inlineを宣言することができます。そのため、コンパイラは可能な限り関数呼び出しのオーバーヘッドを避けたいと考えています。

+0

Aahについての質問ですが、マクロはタイプを確認できるいくつかのコードに展開される可能性があります。例えば、assert(sizeof(reg16)== 4)を使ってマクロ内の引数のサイズを調べることができます。なぜ型ではないのですか? – Rocketmagnet

+0

とにかく、ulidtkoに対する私のコメントで述べたように、関数メソッドは警告もエラーも生成しません!クレイジー、私は知っている。だから私はマクロを使ってやろうとしていたのです。 – Rocketmagnet

+4

残念ながら、Cでの型検査は、間違った列挙の使用を検出するのに十分厳密ではありません。列挙型の厳密な型検査(たとえば、C++)を持つ言語に変更するか、厳密な規則を列挙型に適用するコードチェッカーを使用する必要があります。 –

6

gccをサポートするタイプ

Linuxカーネルから得られるタイプセーフな最小マクロ

#define min(x,y) ({ \ 
    typeof(x) _x = (x); \ 
    typeof(y) _y = (y); \ 
    (void) (&_x == &_y);  \ 
    _x < _y ? _x : _y; }) 

しかし、2つのタイプを比較することはできません。警告を生成しますポインタ比較のに注意 - あなたはこのようなです。TypeCheckを行うことができます(また、Linuxカーネルから)

#define typecheck(type,x) \ 
({ type __dummy; \ 
    typeof(x) __dummy2; \ 
    (void)(&__dummy == &__dummy2); \ 
    1; \ 
}) 

は、おそらくあなたが似た何かができる - すなわち、引数へのポインタを比較します。

5

Cでの型検査は、整数関連型では少し緩いです。ほとんどのポインタ型が互換性がないという事実を利用して、コンパイラを騙すことができます。

ので

#define CHECK_TYPE(var,type) { __typeof(var) *__tmp; __tmp = (type *)NULL; } 

種類が同じでない場合、これが警告、「互換性のないポインタ型からの割り当て」を提供します。たとえば、

私は確かにこれのためのコンパイラのエラーを取得する方法があります。

+1

どこかにタイプミスはありますか? __tmpから一つのアンダースコアを削除しなければならなかった。しかし、私はまだ "エラー:割り当てで無効な左辺値"を受け取ります。 – Rocketmagnet

+0

OK、0 &&も削除しました。今それは動作するようです! – Rocketmagnet

+0

訂正していただきありがとうございます.2つの修正を行いました。私は0 &&トリックはnullポインタの逆参照を防止すると思ったが、それは完全に不要です。次回は、コードをコピーするときに、コードをコピーして貼り付けるだけで、コードをコピーして貼り付けます。 – user295691

関連する問題