タグ付けされた質問 「undefined-behavior」

言語の規則に違反するプログラムのコンパイルまたは実行の予期しない結果は、コンパイラー、インタープリター、ランタイムシステムのいずれも強制する必要はありません。「未定義」のデータ型または戻り値に関する質問には、このタグを使用しないでください。そのような場合は、代わりに[undefined]タグを使用する必要があります。

5
未定義の動作とシーケンスポイント
「シーケンスポイント」とは何ですか? 未定義の動作とシーケンスポイントの関係は何ですか? a[++i] = i;気分を良くするために、のように面白い複雑な表現をよく使用します。それらの使用をやめるべきなのはなぜですか? これを読んだ場合は、フォローアップの質問Undefined behavior and sequence points reloadedにアクセスしてください。 (注:これは、Stack OverflowのC ++ FAQへのエントリになることを目的としています。このフォームでFAQを提供するという考えを批評したい場合は、これをすべて開始したメタへの投稿がそのための場所になります。回答その質問は、C ++チャットルームで監視されます。ここでは、FAQのアイデアが最初から始まっているため、アイデアを思いついた人があなたの答えを読む可能性が非常に高くなります。




5
C ++標準では、初期化されていないブールがプログラムをクラッシュさせることを許可していますか?
C ++の「未定義の動作」により、コンパイラーが必要なことをほとんど実行できることがわかっています。しかし、コードが十分に安全であると思っていたので、驚いたクラッシュがありました。 この場合、実際の問題は、特定のコンパイラを使用する特定のプラットフォームでのみ、最適化が有効になっている場合にのみ発生しました。 問題を再現し、それを最大限に簡略化するために、いくつかのことを試みました。Serializeこれはと呼ばれる関数の抜粋です。これはboolパラメータを取り、文字列trueまたはfalse既存の宛先バッファにコピーします。 この関数はコードレビューに含まれますか?実際には、ブールパラメーターが初期化されていない値である場合にクラッシュする可能性があることを伝える方法はありませんか? // Zero-filled global buffer of 16 characters char destBuffer[16]; void Serialize(bool boolValue) { // Determine which string to print based on boolValue const char* whichString = boolValue ? "true" : "false"; // Compute the length of the string we selected const size_t len = strlen(whichString); …

22
初期化されていないローカル変数は最速の乱数ジェネレータですか?
初期化されていないローカル変数が未定義の動作(UB)であることを知っています。また、値にはトラップ表現があり、それが以降の操作に影響を与える可能性があります。ただし、乱数を視覚的表現にのみ使用し、それ以外の部分では使用しない場合もあります。たとえば、プログラムを視覚効果にランダムな色で設定します。次に例を示します。 void updateEffect(){ for(int i=0;i<1000;i++){ int r; int g; int b; star[i].setColor(r%255,g%255,b%255); bool isVisible; star[i].setVisible(isVisible); } } それよりも速いですか void updateEffect(){ for(int i=0;i<1000;i++){ star[i].setColor(rand()%255,rand()%255,rand()%255); star[i].setVisible(rand()%2==0?true:false); } } また、他の乱数ジェネレータよりも高速ですか?

11
なぜf(i = -1、i = -1)が未定義の動作なのですか?
私は評価違反の順序について読んでいて、私を困惑させる例を示しています。 1)スカラーオブジェクトの副作用が同じスカラーオブジェクトの別の副作用と比較してシーケンスされていない場合、動作は未定義です。 // snip f(i = -1, i = -1); // undefined behavior このコンテキストでiは、は明らかにスカラーオブジェクトです。 算術型(3.9.1)、列挙型、ポインター型、メンバー型へのポインター(3.9.2)、std :: nullptr_t、およびこれらの型のcv修飾バージョン(3.9.3)は、まとめてスカラー型と呼ばれます。 その場合、ステートメントがどのようにあいまいであるかはわかりません。最初または2番目の引数が最初に評価されるかどうかに関係なく、i最終的に-1、および両方の引数もであるように思え-1ます。 誰かが明確にしてもらえますか? 更新 私はすべての議論に本当に感謝しています。これまでのところ、@ harmicの回答は非常に気に入っています。一見しただけではわかりやすいにもかかわらず、このステートメントを定義する際の落とし穴と複雑さを明らかにしているからです。@ acheong87は、参照を使用するときに発生するいくつかの問題を指摘していますが、これは、この質問のシーケンスされていない副作用の側面とは直交していると思います。 概要 この質問はかなりの注目を集めたので、主なポイント/回答を要約します。まず、少し補足して、「なぜ」は密接に関連しているが微妙に異なる意味を持つ可能性があることを指摘します。つまり、「原因」、「理由」、および「目的」です。私は、答えが「なぜ」のそれらの意味のどれに対処したかによってグループ分けします。 何のために ここでの主な答えは、Paul Draperからのもので、Martin Jが同様の貢献をしましたが、それほど広くはありません。ポール・ドレイパーの答えは要約されます 動作が定義されていないため、未定義の動作です。 答えは、C ++標準の内容を説明するという点で、全体的に非常に優れています。また、f(++i, ++i);やなど、UBのいくつかの関連するケースも扱いますf(i=1, i=-1);。関連する最初のケースでは、最初の引数が必要かどうかi+1、2番目の引数が必要かどうか、i+2またはその逆が明確ではありません。2番目でiは、関数呼び出しの後に1か-1 かが明確ではありません。これらのケースはどちらも次のルールに該当するため、UBです。 スカラーオブジェクトの副作用が同じスカラーオブジェクトの別の副作用と比較してシーケンスされていない場合、動作は未定義です。 したがって、f(i=-1, i=-1)プログラマの意図が(IMHO)明白で明確であるにもかかわらず、同じ規則に該当するため、UBもです。 ポール・ドレイパーはまた、彼の結論でそれを明確にしています 動作が定義されているのでしょうか?はい。定義されましたか?番号。 「どのような理由/目的がf(i=-1, i=-1)未定義の動作として残されたのか?」 どのような理由/目的で C ++標準にはいくつかの見落とし(多分不注意)がありますが、多くの省略は十分な理由があり、特定の目的を果たします。目的は「コンパイラライターの仕事を簡単にする」または「コードを高速にする」のいずれかであることが多いことは承知していますが、主に UBのままにする正当な理由があるかどうかを知りたいと思っていましたf(i=-1, i=-1) 。 harmicとsupercatは、UBの理由を提供する主な答えを提供します。Harmicは、見かけ上アトミックな割り当て操作を複数の機械語命令に分割する可能性のある最適化コンパイラーと、それらの命令をさらにインターリーブして最適な速度にする可能性があることを指摘しています。これはいくつかの非常に驚くべき結果につながる可能性があります:i彼のシナリオでは-2になります!したがって、harmicは、操作がシーケンスされていない場合に、変数に同じ値を複数回割り当てると悪影響を与える可能性があることを示しています。 supercatは、本来あるf(i=-1, …

14
一部のプラットフォームでこのforループが終了し、他のプラットフォームでは終了しないのはなぜですか?
最近Cを学び始め、Cを題材にした授業を行っています。私は現在ループで遊んでいて、説明の方法がわからない奇妙な動作に遭遇しています。 #include <stdio.h> int main() { int array[10],i; for (i = 0; i <=10 ; i++) { array[i]=0; /*code should never terminate*/ printf("test \n"); } printf("%d \n", sizeof(array)/sizeof(int)); return 0; } Ubuntu 14.04を実行している私のラップトップでは、このコードは壊れません。それは完了するまで実行されます。CentOS 6.6を実行している私の学校のコンピューターでも、問題なく動作します。Windows 8.1では、ループが終了することはありません。 さらに奇妙なのは、forループの条件を次のように編集するi <= 11と、コードがUbuntuを実行しているラップトップでのみ終了することです。CentOSとWindowsでは終了しません。 メモリで何が起こっているのか、同じコードを実行している異なるOSが異なる結果をもたらす理由を誰かが説明できますか? 編集:forループが範囲外になることを知っています。わざとやってます。OSやコンピューターによって動作がどのように異なるのかがわかりません。

5
なぜ符号なし整数オーバーフローは動作が定義されていますが、符号付き整数オーバーフローは定義されていないのですか?
符号なし整数オーバーフローは、CおよびC ++標準の両方で明確に定義されています。たとえば、C99標準(§6.2.5/9)は 結果の符号なし整数型で表すことができない結果は、結果の型で表すことができる最大値よりも1大きい数を法として減じられるため、符号なしオペランドを伴う計算は決してオーバーフローできません。 ただし、どちらの規格も、符号付き整数オーバーフローは未定義の動作であると述べています。ここでも、C99標準(§3.4.3/1)から 未定義の動作の例は、整数オーバーフローでの動作です この矛盾の歴史的または(さらに良い!)技術的な理由はありますか?

11
C ++プログラマが知っておくべき一般的な未定義の動作は何ですか?[閉まっている]
ここで何が質問されているのかを理解するのは困難です。この質問は、あいまいで、あいまいで、不完全で、過度に広い、または修辞的であり、現在の形では合理的に回答することができません。再開できるようにこの質問を明確にするヘルプについては、ヘルプセンターに アクセスしてください。 7年前休業。 ロックされています。質問はトピックから外れていますが、歴史的に重要であるため、この質問とその回答はロックされています。現在、新しい回答や相互作用を受け入れていません。 C ++プログラマが知っておくべき一般的な未定義の動作は何ですか? 次のように言います: a[i] = i++;

15
実際には、なぜ異なるコンパイラがint x = ++ i + ++ i;の異なる値を計算するのでしょうか?
このコードを検討してください: int i = 1; int x = ++i + ++i; コンパイラーがこのコードをコンパイルすると仮定して、このコードに対して何を行うかについては、いくつかの推測があります。 両方とも++i戻り2、結果としてx=4。 1つ++iは戻り2、もう1つはを返し3、結果としてx=5。 両方とも++i戻り3、結果としてx=6。 私には、2番目の可能性が最も高いようです。2つの++演算子の1つがで実行されi = 1、iがインクリメントされ、結果2が返されます。次に、2番目の++演算子がで実行されi = 2、iがインクリメントされ、結果3が返されます。次に2、と3を足し合わせてを与え5ます。 ただし、このコードをVisual Studioで実行したところ、結果はでした6。私はコンパイラをよりよく理解しようとしていますが、何が結果につながる可能性があるのか​​疑問に思ってい6ます。私の唯一の推測は、コードは「組み込み」の並行性で実行できるということです。2つの++演算子が呼び出され、それぞれiがもう一方が戻る前にインクリメントされ、その後、両方ともが返されました3。これは、コールスタックの私の理解と矛盾するため、説明する必要があります。 結果またはC++結果につながるコンパイラーが実行できる(合理的な)ことは何ですか?46 注意 この例は、Bjarne Stroustrupのプログラミング:C ++(C ++ 14)を使用した原則と実践における未定義の動作の例として登場しました。 シナモンのコメントを参照してください。

5
なぜこのループは「警告:反復3uが未定義の動作を呼び出す」ので、4行以上出力するのですか?
これをコンパイルする: #include <iostream> int main() { for (int i = 0; i < 4; ++i) std::cout << i*1000000000 << std::endl; } そしてgcc次の警告を生成します: warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations] std::cout << i*1000000000 << std::endl; ^ 符号付き整数オーバーフローがあることを理解しています。 iオーバーフロー操作によって値が壊れるのはなぜですか。 私は答えを読んだのはなぜ無限ループ原因GCCとのx86上でオーバーフロー、整数のでしょうか?、しかし、なぜこれが起こるのかはまだはっきりしていません-「未定義」は「何かが起こる可能性がある」という意味ですが、この特定の動作の根本的な原因は何ですか? オンライン:http : //ideone.com/dMrRKR コンパイラ: gcc (4.8)

8
「while(1);」を最適化する C ++ 0x
更新されました、以下を参照してください! C ++ 0xを使用すると、コンパイラーが次のスニペットの「Hello」を出力できるようになる #include <iostream> int main() { while(1) ; std::cout << "Hello" << std::endl; } スレッドと最適化機能に関係しているようです。しかし、これは多くの人を驚かせる可能性があるようです。 許可するためにこれが必要だった理由について誰かが良い説明をしていますか?参考までに、最新のC ++ 0xドラフトは次のように述べています。6.5/5 forステートメントの場合のfor-init-statementの外側のループ ライブラリI / O関数を呼び出さない。 揮発性オブジェクトにアクセスまたは変更しない、および 同期操作(1.10)またはアトミック操作(29節)を実行しない 実装は終了すると想定できます。[注:これは、終了が証明できない場合でも、空のループの削除などのコンパイラ変換を可能にすることを目的としています。—エンドノート] 編集: この洞察に満ちた記事は、その標準テキストについて述べています 残念ながら、「未定義の動作」という言葉は使用されていません。ただし、標準で「コンパイラはPを想定している可能性があります」と記載されている場合は常に、not-Pプロパティを持つプログラムはセマンティクスが未定義であることを意味します。 それは正しいですか、コンパイラは上記のプログラムの「バイ」を出力することを許可されていますか? ここにはさらに洞察に満ちたスレッドがあります。これはCへの類似の変更に関するもので、上記のリンクされた記事を書いた人によって開始されました。他の有用な事実の中で、それらはC ++ 0xにも適用されると思われる解決策を提示します(更新:これはn3225ではもう機能しません-下記を参照してください!) endless: goto endless; コンパイラはループではなくジャンプなので、それを最適化することはできません。別の男はC ++ 0xとC201Xで提案された変更を要約します ループを書き込むことによって、プログラマがアサートされているいずれかのループは、可視挙動を有するもの(実行I / O、アクセス揮発性オブジェクト、または実行同期または原子操作)をしていること、 またはそれが最終的に終了すること。副作用のない無限ループを作成してその仮定に違反すると、コンパイラーに嘘をついてしまい、プログラムの動作は未定義になります。(運が良ければ、コンパイラーが警告するかもしれません。)この言語は、目に見える動作なしで無限ループを表現する方法を提供していません(提供していませんか?)。 2011年3月31日にn3225で更新:委員会はテキストを1.10 / 24に移動し、 実装は、すべてのスレッドが最終的に次のいずれかを実行すると想定する場合があります。 終了、 …

5
拡張GCC 6オプティマイザが実用的なC ++コードを壊すのはなぜですか?
GCC 6には新しいオプティマイザ機能があります。それthisは常にがnull ではないことを想定し、それに基づいて最適化します。 値の範囲の伝播は、C ++メンバー関数のthisポインターがnullでないことを前提としています。これにより、一般的なnullポインターチェックが不要になりますが、一部の非準拠コードベース(Qt-5、Chromium、KDevelopなど)も破損します。一時的な回避策として、-fno-delete-null-pointer-checksを使用できます。間違ったコードは、-fsanitize = undefinedを使用して識別できます。 変更文書は、頻繁に使用される驚くべき量のコードを破壊するため、これを危険だと明確に呼んでいます。 なぜこの新しい仮定が実用的なC ++コードを壊すのでしょうか?不注意または知識のないプログラマーがこの特定の未定義の動作に依存する特定のパターンはありますか?if (this == NULL)不自然なため、誰も書いていないようです。

6
GCCを使用するx86で整数オーバーフローが無限ループを引き起こすのはなぜですか?
次のコードは、GCCの無限ループに入ります。 #include <iostream> using namespace std; int main(){ int i = 0x10000000; int c = 0; do{ c++; i += i; cout << i << endl; }while (i > 0); cout << c << endl; return 0; } だからここでの取り決めです:符号付き整数オーバーフローは技術的に未定義の動作です。しかし、x86上のGCCは、オーバーフローでラップするx86整数命令を使用して整数演算を実装します。 したがって、未定義の動作であるにもかかわらず、オーバーフローでラップすることを期待していました。しかし、明らかにそうではありません。それで私は何を逃したのですか? 私はこれを使ってこれをコンパイルしました: ~/Desktop$ g++ main.cpp -O2 GCC出力: ~/Desktop$ ./a.out 536870912 1073741824 …
129 c++  c  gcc  x86  undefined-behavior 

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.