C整数変数が署名されているかどうかを確認するにはどうすればよいですか?
-
05-07-2019 - |
質問
演習として、整数変数が署名されているかどうかを通知するマクロを作成したいと思います。これは私がこれまでに持っているものであり、gcc -fsigned-charまたは-funsigned-charを使用してchar変数でこれを試してみると、期待どおりの結果が得られます。
#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0)
これはポータブルですか?変数の値を破壊せずにこれを行う方法はありますか?
解決
#define ISVARSIGNED(V) ((V)<0 || (-V)<0 || (V-1)<0)
Vの値は変更しません。3番目のテストでは、V == 0の場合を処理します。
私のコンパイラ(gcc / cygwin)では、これはint
およびlong
で機能しますが、char
またはshort
では機能しません。
#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0)
また、2つのテストでジョブを実行します。
他のヒント
GCCを使用している場合、値を上書きしないようにtypeof
キーワードを使用できます。
#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 })
これにより、_V
と同じ型の一時変数V
が作成されます。
移植性に関しては、わかりません。それは2の補数マシン(つまり、コードがすべての確率で実行されるすべてのもの)で動作し、私はそれが1つの補数およびサインアンドマグニチュードマシンでも動作すると信じています。補足説明として、-1
を使用する場合は、typeof (V)
を<=>にキャストしてより安全にする(つまり、警告をトリガーする可能性を低くする)ことができます。
#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0))
変数の値を破壊することなく。ただし、値が0の場合は機能しません。
概要:
#define ISVARSIGNED(V) (((V)-(V)-1) < 0)
すべての<!> quot;をネガティブにする<!> quot;回答:
#define ISVARSIGNED(V) (~(V^V)<0)
このように、<!>#8704;のように、Vの異なる値に対して特別なケースを用意する必要はありません。 V <!>#8712; <!>#8484;、V ^ V = 0。
この単純なソリューションには、vを1回だけ参照するという利点(マクロで重要)を含め、副作用はありません。 gcc拡張機能<!> quot; typeof <!> quot;を使用します。 vの型を取得し、-1をこの型にキャストします:
#define IS_SIGNED_TYPE(v) ((typeof(v))-1 <= 0)
<!> lt;ではなく<!> lt; =です。場合によってはコンパイラの警告を回避するため(有効な場合)。
なぜ地球上でマクロにする必要があるのですか?テンプレートはこれに最適です:
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;
}
基本的なすべての整数型に対して、そのまま使用できます。また、ポインターのコンパイル時に失敗しますが、減算と比較のみを使用するバージョンではおそらく失敗しません。
編集:おっと、質問にはCが必要です。それでも、テンプレートは良い方法です:P
符号付き/符号なしの数学の特徴は、符号付き数値を右にシフトすると、最上位ビットがコピーされることです。符号なしの数値をシフトすると、新しいビットは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の補数演算を前提としていますが、通常は安全な前提です。