![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
算術右シフトと論理右シフトをC言語にて実装しようとしています。
『ハッカーのたのしみ』にある論理右シフトを用いて算術右シフトを作る方法を使おうと思っているのですが、C言語で確実に論理右シフトするにはどうすればよいのでしょうか。
int x;
(unsigned int) x >>= n;
とするとgccではゼロ拡張してくれるようなのですが、
use of cast expressions as lvalues is deprecated
というWarningが出ます。
この方法が確実とは思えませんし、
unsigned int xx;
xx = x;
も処理系依存と聞きます。
出来ればWarningが出ない形で解決したいのですが、どうすればよいのでしょうか。
教えてください。
No.5ベストアンサー
- 回答日時:
ああ, よく考えれば「最初から unsigned で全部処理をする」というのが最も正しい解のような気がします.
それはさておき, 右シフト演算子の左オペランドが signed で負数の場合, 結果は「実装定義」です. 未定義ではありません.
ついでにいうと, signed → unsigned のキャストは 6.3.1.3節のパラグラフ2 にあるように変換されます. 本当は JIS を参照するのが正しいんだけど ISO しか持ってないのでこっちを参照すると
If the new type is unisgned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
となっていて, signed int → unsigned int の場合には実質的に「もともとが正ならそのまま, 負なら UINT_MAX+1 を加えた値」となります. ということで 2の補数を使っていればたいていはビットパターンが変化しません.
逆に unsigned → signed の場合は「signed で表現できればそのまま, 表現できなければ実装定義」となります.
ちなみに C++ だと signed → unsigned の変換は「2^n を法として最小の整数」で, 2の補数を使ってる場合には同じことですね.
ん~, 「unsigned int xx; xx = x; も処理系依存」というのも, 本当にここまで考えて書いているのかなぁ....
しつこく付き合わせてしまい申し訳ありません。
未定義ではなく実装定義ですね。
日本語が理解できていなかったようです orz。
unsigned int xx;
xx = x;
はxとxxのビットパターンが同じになるかどうか不安という意味で書きました。
今回のことで、一度仕様書を通読する機会を持つ必要を感じました。
土方志望では無いのですが、せめて人並みには使えるように頑張ろうと思います。
No.4
- 回答日時:
Warningが出るのは、左辺値をcastしているからだと思います。
質問の実装をするのであれば、
int x;
unsigned int x_tmp;
x_tmp = (unsigned int)x;
x_tmp >>= n;
としてみては如何でしょうか。
ただ、m_11さんがおっしゃるとおり、処理系に依存するので、必ずしも成功するとは限りません。
No.3
- 回答日時:
あれ? 真意が伝わっていない気が....
ISO C の規格によれば, (右オペランドが非負かつ左オペランドのビット幅未満の値を持っているという前提のもとで) 左オペランドが unsigned なら全ての処理系において予測可能な結果となりますが, signed の場合には (右シフトかつ負のとき) 実装定義の結果となったり (左シフトでその結果が表現できる値を越える場合には) 未定義動作となります.
ということで, 左オペランドを signed のまま扱うのは危険ですからなんとかして unsigned にする必要があります.
これは, 普通の環境では「単に unsigned にキャストするだけ」で実現できます. 正確には, 「signed の表現が全ビット幅を用いた 2の補数表現」かつ「可能な全ビットパターンに対して unsigned で値が有効」であれば実現可能です.
ということで, 普通の環境であれば
x = (int)((unsigned)x >> n);
で x の値を右に nビット論理シフトすることができます.
普通じゃない環境, 例えば負数を表現するのに「1の補数」を使ってみたり「符号+絶対値」であったりするような環境ではうまくいかないので, そういう環境 (現存するかどうかは知りません) も考慮するなら「努力と根性」が待っています. もちろんこんな環境を考慮するくらいなら
x >> 1
すら危険ですが.
signedで負数を右シフトしたときの結果は"未定義"だったのですね。
算術シフトか、論理シフトのどちらかになるものと勘違いしていました。
さすがに、負数表現に2の補数を用いない機械を相手にする気はありませんので、
x = (int)((unsigned int) x >> n);
で良いと聞いて安心しました。
かなり広範囲の環境で、unsignedへのキャストはキャスト前と同じビットパターンになることが確実との情報も有益でした。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- 情報処理技術者・Microsoft認定資格 2進数の問題を教えてください。 1 2022/07/27 09:42
- 計算機科学 空系列を用いたもので、 2 2022/12/12 01:36
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- Excel(エクセル) エクセルでセルを挿入するとき、デフォルトのシフト方向を変更したい 3 2023/08/02 18:17
- Excel(エクセル) 月間シフト表から総勤務時間を計算する関数 4 2023/05/20 07:12
- C言語・C++・C# C++言語の16進数の表現についておしえてください 1 2022/11/14 17:46
- 労働相談 異動をちらつかせる上司について 3 2023/07/29 21:23
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# C言語 共用体について コマンドライン引数で値を2つ入力したときに、argv[2]の値をUNI u1 4 2022/04/25 20:34
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
16進数 加算 減算 C言語
-
c languageで 簡単な質問があ...
-
VB.net Double と...
-
”/”を使わずに割り算したいんで...
-
VBAでミリ秒まで出力する方法
-
EXCELの関数"STDEV(標準偏差)"...
-
O(n log n)について2
-
ExcelのINT関数の計算結果がお...
-
除算を使わずに10で割りたい。
-
floatの有効桁数
-
数値計算で生じる小さなごみ
-
Excel VBAでの数値の計算につい...
-
距離から緯度経度を求める方法
-
計算の丸め誤差の解消について
-
C言語でセルオートマトンを作成...
-
Log関数に関する質問
-
100桁の計算ができなくて困って...
-
verilog ALU
-
【C++】double の計算結果がお...
-
この計算プログラムの書き方を...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
O(n log n)について2
-
16進数 加算 減算 C言語
-
c languageで 簡単な質問があ...
-
ExcelでPC(パソコン)によって...
-
”/”を使わずに割り算したいんで...
-
有効数字について 以前質問をし...
-
三角比の俯角の計算
-
ExcelのINT関数の計算結果がお...
-
VB.net Double と...
-
floatの有効桁数
-
パソコンで階乗を計算
-
三菱シーケンサ(Aシリーズ)で...
-
除算を使わずに10で割りたい。
-
VB6.0での小数点の扱いについて
-
EXCELの関数"STDEV(標準偏差)"...
-
時刻の比較
-
VBAでの割り算の余りの求め方
-
計算の丸め誤差の解消について
-
C言語プログラミングにて、arct...
-
VBAでミリ秒まで出力する方法
おすすめ情報