2009-09-11 19 views
7

練習として、整数変数が署名されているかどうかを示すマクロを記述したいと思います。これは私がこれまで行ってきたことであり、gcc -fsigned-charまたは-funsigned-charを使ってchar変数でこれを試してみると、私が期待した結果が得られます。Cの整数変数が署名されているかどうかを確認するにはどうすればよいですか?

#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0) 

これは移植可能ですか?変数の値を破壊することなくこれを行う方法はありますか?

+0

これは興味深い問題ですが、私はこの情報の意図した使い方によってはるかに興味を持っていますです。共有する機会はありますか? –

+0

これはC++にRTTIがある理由です。 :) –

+2

@jeffamaphone:実際には、これはC++でテンプレートが輝く場所です。 – sbi

答えて

4
#define ISVARSIGNED(V) ((V)<0 || (-V)<0 || (V-1)<0) 

第3の試験は、私のコンパイラ(GCC/cygwinの)でV == 0

ケースを扱うVの値を変更しない、これはintlongためではなくcharの作品またはshort

#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0) 

も2つのテストでジョブを実行します。

+0

私はまだ見たことがあります。ポータブル、標準準拠、正確な限り私は見ることができます。 –

+1

signed/unsigned shortとcharを区別しません。これらの型は、< == >の式を評価するときにintに昇格されます。 – mob

+0

'short'と' char'で動作させたい場合は、使用する前にその変数を 'char'にキャストすることができます。それはほとんどのオーバーフローの問題を処理する必要があります。私はそう思う... –

5
#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0)) 

変数の値を破壊することなく。しかし、0の値では機能しません。

何について

:あなたはGCCを使用している場合は、値を上書きしないようにtypeofキーワードを使用することができます

#define ISVARSIGNED(V) (((V)-(V)-1) < 0) 
+3

#define ISVARSIGNED(V)((-V <0)!=(V <0)) – plinth

+0

その冗長なもの;-) – ypnos

+0

@plinth、あなたは狂ったマクロ展開から安全にする 'V'の周りの "余分な"括弧を忘れた – rmeador

5

#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 }) 

これは持っている一時変数、_Vを作成しますVと同じタイプです。

移植性についてはわかりません。それは2の補完マシン(あなたのコードがすべての確率で実行されるすべてのもの)で動作し、私はそれが自分の褒めとサインアンドマグニチュードマシンでも動作すると信じています。副題として、typeofを使用している場合は、より安全に(つまり、警告を引き起こす可能性が低い)ように-1typeof (V)にキャストしてください。

+0

C++では、整数表現(nビットの場合、値は2^n - 1)にかかわらず、Standardによって動作することが保証されています。私はCの標準を手に入れることはできません。 –

+0

私もそうではありませんが、C標準が私が挙げた3つの表現を許しているというWikipedia(すべての事実の出典:P)に関する読書を思い出しています。誰もそれらをもう使用しない... –

-1

符号付き/符号なし演算の特徴は、符号付き数値を右シフトすると、最上位ビットがコピーされることです。あなたは、符号なしの数をシフトする場合、新しいビットが0

#define HIGH_BIT(n) ((n) & (1 << sizeof(n) * CHAR_BITS - 1)) 
#define IS_SIGNED(n) (HIGH_BIT(n) ? HIGH_BIT(n >> 1) != 0 : HIGH_BIT(~n >> 1) != 0 

されるように、基本的に、このマクロは数の高いビットがセットされているかどうかを決定するための条件式を使用します。そうでなければ、マクロはビット数を否定することによってそれを設定します。 -0 == 0なので算術否定はできません。次に、右に1ビットシフトし、符号拡張が発生したかどうかをテストします。

これは2の補数演算を前提としていますが、これは通常安全な前提です。

+0

ビットシフトの動作についてのこれらの前提についての情報源はありますか? –

+0

C99標準(6.5.7項)では、符号付き負の値の右シフトは実装定義であると言います。私の解釈は、2の補完機械に符号拡張があることです。 Cは2の補数アーキテクチャに固有なものではないので、出てくることはありません。 –

+0

あなたは、魔法の '8'の代わりに' CHAR_BITS'を使うことでより多くのPCになるでしょう。 (はい、私は知っている、私たちのうちのほんの少数は、バイトが8ビットのマシンでは動作していません。まだ。) – sbi

1

この単純なソリューションには、vを一度しか参照しない(マクロで重要な)メリットを含め、副作用がありません。我々は、Vの型を取得するためにgccの拡張子「typeof演算」を使用して、キャスト-1このタイプに:

#define IS_SIGNED_TYPE(v) ((typeof(v))-1 <= 0) 

それは< =だけでなく<(有効な場合)いくつかのケースのためのコンパイラの警告を回避するためです。

0

なぜマクロである必要がありますか?テンプレートはこれに最適です:

template <typename T> 
bool is_signed(T) { 
    static_assert(std::numeric_limits<T>::is_specialized, "Specialize std::numeric_limits<T>"); 
    return std::numeric_limits<T>::is_signed; 
} 

すべての基本的な整数型ですぐに使用できます。ポインタのコンパイル時にも失敗します。これは、減算と比較のみを使用するバージョンはおそらくそうではありません。

EDIT:P

0

すべて "それは否定します" の答えに異なるアプローチ:

#define ISVARSIGNED(V) (~(V^V)<0) 

その方法おっと、質問はC.はまだ、テンプレートが素敵な方法ですが必要ですV≠0、V^V = 0なので、異なる値のVに対して特殊なケースを持つ必要はありません。

関連する問題