
C++17では非推奨だったbool型に対するインクリメント演算子の利用が不可能に 65
ストーリー by hylom
そもそもの挙動が分かりにくい感じ 部門より
そもそもの挙動が分かりにくい感じ 部門より
C++言語の新標準規格である「C++17」では、bool型に対する++演算子が利用できなくなるそうだ(cpprefjp - C++日本語リファレンス)。今まではbool型の変数に対し++演算子を適用すると、その変数の値をtrueにするという仕様となっていた。
なお、C言語にはbool型が存在しないため、int型をbool型の代用として使用することが良くあった。この場合、C++の仕様と同様に++演算子を適用するとその値は必ず1以上、つまりtrueになるように見える。しかし、変数の値がint型に格納できる最大値(たとばintが8ビットの場合255)になっていた場合、++演算子を適用するとオーバーフローが発生してその値は0、つまりfalseになってしまうという問題があった。
cpprefjp - C++日本語リファレンスによると、放射線療法機器「セラック25」ではこのバグが原因で死者を出す事故が発生していたという。
セラック25 (スコア:3, 興味深い)
Cではなくアセンブリ言語で書かれていたようです。
https://en.wikipedia.org/wiki/Therac-25 [wikipedia.org]
アセンブリ言語ならこういう書き方をするのもわかる気がしますが、
そのバグがC++の仕様に影響を与えていたとは。。。
gcc -std=c99 (スコア:2)
_Bool型あります。
_Bool a,b;
a = 1;
b = a+a;
printf(("%d\n",b);
printf(("%d\n",(_Bool)(-1));
は共に1を表示します。
Re:gcc -std=c99 (スコア:1)
gccはかなり成績いいけど、
もうちょっとマイナーなccの_Boolを本気でアラ探しすると、
結構面倒なこと [ludd.ltu.se]になるよ
Re: (スコア:0, 荒らし)
gccのboolって、結局8bit or 16bit intでなかったでしたっけ?
数年前、On/Offのフラグを320万個くらい確保しなくてならなくて
必要なメモリ確保量に悲鳴を上げた覚えが。
それならint型で配列確保するがな。
boolって、それを1bitで実現できるから便利なんだと思いましたですよ。
#結局、8bit charを分解して1bitごとのbool代数にするライブラリを
#独自開発して繰り延べ。
#そういや、ユーザがこのストーリーにある「++」演算子をする可能性は全く考えてなかったw
#まあ、俺が開発して俺が使うライブラリだからいいっかー
Re:gcc -std=c99 (スコア:1)
そうです。C++のboolもC99のboolも、&演算子でアドレスを取得できる必要がある、という理由で、1バイト以上の大きさが必須となっています。
ビット単位でのストレージは、C++ならクラス作ってなんとかしろということで、std::bitset<>、std::vector<bool>、boost::dynamic_bitsetなどが生まれましたね。
255回に1回ポロリするbool (スコア:1)
その挙動に依存していたせいで、修正後さらに死者を出すような事態にならないことを祈る
Re: (スコア:0)
なくなるんだから、依存課所はコンパイルエラーになるんとちゃうの?
#PHPではならないから地獄。Web専用言語のくせに全部実行時エラーとかアホか。
Re: (スコア:0)
上でも書かれてるように、intに#defineなりtypedefなりって修正をするとエラーを吐かなくなるから……
Re: (スコア:0)
ん?ポロリするのは256回に1回では?
Lisper「そもそもブーリアン型って必要なの?」 (スコア:1)
falseや#f、nilのような特殊なシンボル以外は、あらゆる値が真扱いでいいだろ
下手にtrueとか無駄な状態を作ろうとするからおかしなことになるんだよ
なにがオーバーフローだよ、知らねえよバカ
#fじゃねえんだったら、値がゼロだろうがマイナスになろうが変数がまだ未初期化だったとしても黙って真を返して来りゃいいんだよ
Re:Lisper「そもそもブーリアン型って必要なの?」 (スコア:2, 参考になる)
西城秀樹いわく、いつかはブーリアン型に回帰すると
Re:Lisper「そもそもブーリアン型って必要なの?」 (スコア:2)
何で「参考になる」なんだ……
#ぶーりあんぶーりあんきっとー
Re: (スコア:0)
けど、この実装って、オーバーヘッドでるよね?
Re: (スコア:0)
それでは(コンパイラが最適化するのに)効率が悪いから _Bool が導入されてる。
Re:Lisper「そもそもブーリアン型って必要なの?」 (スコア:1)
非ゼロを全部1にfoldする必要がある_Boolのほうが効率悪くない? CPUにはたいていゼロテストの命令がある。
Re: (スコア:0)
ちゃんと処理しておかないと、true & true がfalseになる場合があるからかな~と想像してみる。
a=false ;
a++ ; // aはtrue(intで1)
b=a ;
b++ ; // bはtrue(intで2)
c=a&b ; // cはtrue?
Re: (スコア:0)
Javaはこういうアホな仕様を排除 (スコア:0)
Javaはこういうアホな仕様を排除してて良いんだよね。
Re:Javaはこういうアホな仕様を排除 (スコア:1)
オブジェクト同士の == が参照が同じかどうか比較というアホな仕様をどうにかしてくれませんかね。
Re: (スコア:0)
(Cでいう)ぽぽぽポインタの比較だから!あ、あってるから!
Re: (スコア:0)
普通equls()を使うよな。使うというか作るのだが。オーバーライドセずにそのまま使うと==と同じことになるし。ま、オブジェクトは==を使えないようにして参照先の比較はcheckPointer(obj1,obj2)とかにすればもっとよかったんだろうけど。
初心者はStringとStringを==で繋いじゃうんですよねー。=でつなぐ人もいますけど。まぎらわしーよねー。
Re:Javaはこういうアホな仕様を排除 (スコア:1)
Javaは演算子オーバーライドできない仕様だったから、そうなっちゃった。
C#は最初から演算子オーバーライドできるから、文字列の==は直感的な仕様になってる。
Re:Javaはこういうアホな仕様を排除 (スコア:1)
Javaで文字列を==で比較しているコードは、internしている文字列の比較で正しいコードなのか、equalsではなくあえて==で比較している常識的ではないが正しいコードなのか、ただのバグなのか、理解するのは難しい
C#であれば値としての文字列の比較なので直感的かつ常識的に読み書きできる
高級言語とアセンブラを行ったり来たりしているうちに常識を忘れてしまいましたか?
Re:Javaはこういうアホな仕様を排除 (スコア:1)
初心者はStringとStringを==で繋いじゃうんですよねー。=でつなぐ人もいますけど。まぎらわしーよねー。
ある程度、熟練してても、VB.NETとC#を交互につかうと間違えそうになる。
# 逆にド初心者というか、プログラミングやってない人だと
# i = i + 3;
# みたいな式を見て「!?」となるとか
Re: (スコア:0)
初心者はjava.lang.String#intern()を知りませんからね...。
Re:Javaはこういうアホな仕様を排除 (スコア:1)
演算子オーバーロードを排除したがために、BigInt等の計算がむごいことになってるがな。
まあ理由はフールプルーフの類だが、
「使う人の問題」を言語でなんとかしようとするのは程々にしとくもんだよ。
※あまりにクソな奴は無視しろ!と思うがそういう奴ほど声デカくてうざいんだよねーw
Re: (スコア:0)
だからSIerにはJavaのウケがいいのか
Re: (スコア:0)
C#: せやな
PHP: せやせや
PL/I: 笑止
Re: (スコア:0)
JavaScript: お、===(厳密等価演算子)ぶつけんぞ
Trueそは何者ぞ (スコア:0)
VB「-1ぞ」
Re: (スコア:0)
COM で使われる VARIANT_TRUE も 0xFFFF だから -1 ですな
Re: (スコア:0)
VARIANTとかSAFEARRAYとかはVBの型の一部を他言語で使えるように切り出したようなものだからな。
Re: (スコア:0)
Microsoft Basicから-1でしたね。
トグルスイッチ的な利用法かと思ったら違った (スコア:0)
++する事で0と1が切り替わるのかと
int型→bool型に置き換えた場合に不具合がでないように今の仕様になったんですかね
Re: (スコア:0)
たぶんそうですな。最初からboolでやる人はインクリメントなんかせず絶対代入にするもん。
bool代用でint使うなら普通0か1かですよね…いくら判定がif(a!=0)と扱われるとしてもtrue/false相当とした数字以外に平気でなる組み方はさすがにどうかと。
Re: (スコア:0)
でも、JavaScriptでも似たようなことを無意識でやってる人は多いと思う。
セラック25のバグは (スコア:0)
int型をインクリメントしてboolに変換してたんだから、boolのインクリメントが禁止されても防げなくない? 逆に変数がbool型で宣言されていたらインクリメントしても問題なかった(確実にtrueになることが保証される)。なんでこのバグをC++17の仕様変更と関連付けてるのかまったく意味がわからない。
Re: (スコア:0)
Re: (スコア:0)
仮に8bitのintがあったとして、最大値は127ではないだろうか?
Re: (スコア:0)
それじゃインクリメントしても問題が起きないので、unsignedだと忖度するのでしょう。
Re: (スコア:0)
Z80が寂しそうに見ている。。。
Re: (スコア:0)
Re: (スコア:0)
Z80の時代はANSI以前のCコンパイラも結構ありましたね。LSI-Cの最初のバージョンもそう。
Re: (スコア:0)
ANSIによる標準化以降でもすべてのCコンパイラがそれに準拠してるとも限らんよ
Re: (スコア:0)
ANSI以前でもCPUが8ビットでもintが8ビットな処理系って存在しなかったと思うがなあ。
#charが7ビットな処理系は存在したらしい。(←ANSI違反)
Re: (スコア:0)
BDS-Cもintは16bitあったような。
HI-TECH Cも16bitだったような気がするけど、これは8086だったかな。
Re: (スコア:0)
int の格納には HL レジスタを使っていました > BDS-C (触ったのは α-Cだけど)
Re: (スコア:0)
charは何ビットでもいいがsizeof(char)は必ず1になるんじゃなかったっけ?
Re: (スコア:0)
ANSIで最低8ビットと決められました>char
Re: (スコア:0)
私の初めてのC(エロい)はMSX-Cでしたが、それでもintは16bitありました。