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

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


2
nullインスタンスでメンバー関数を呼び出すと、未定義の動作が発生するのはいつですか?
次のコードを検討してください。 #include <iostream> struct foo { // (a): void bar() { std::cout << "gman was here" << std::endl; } // (b): void baz() { x = 5; } int x; }; int main() { foo* f = 0; f->bar(); // (a) f->baz(); // (b) } nullポインターに(b)対応するメンバーがないため、クラッシュすることが予想されxます。実際に(a)は、thisポインタは使用されないため、クラッシュしません。 ので(b)逆参照thisポインタ((*this).x = 5;)、およびthisnullであるヌルを逆参照することは、常に未定義の動作と言われているように、プログラムは、未定義の動作に入ります。 (a)未定義の動作につながりますか?両方の関数(およびx)が静的である場合はどうなりますか?

9
8ビット整数から8ビットより大きい値を取得するにはどうすればよいですか?
この小さな宝石の後ろに隠れている非常に厄介なバグを見つけました。C ++仕様によると、符号付きオーバーフローは未定義の動作ですが、値がbit-widthに拡張されたときにオーバーフローが発生した場合のみsizeof(int)です。私が理解しているように、のインクリメントは、でcharある限り、未定義の動作であってはなりませんsizeof(char) < sizeof(int)。しかし、それはどのようcにして不可能な価値を得ているのかを説明していません。8ビット整数として、cそのビット幅より大きい値をどのように保持できますか? コード // Compiled with gcc-4.7.2 #include <cstdio> #include <stdint.h> #include <climits> int main() { int8_t c = 0; printf("SCHAR_MIN: %i\n", SCHAR_MIN); printf("SCHAR_MAX: %i\n", SCHAR_MAX); for (int32_t i = 0; i <= 300; i++) printf("c: %i\n", c--); printf("c: %i\n", c); return 0; } 出力 SCHAR_MIN: -128 SCHAR_MAX: …

8
「struct hack」は技術的に未定義の動作ですか?
私が尋ねているのは、よく知られている「構造体の最後のメンバーは可変長です」というトリックです。それはこのようなものになります: struct T { int len; char s[1]; }; struct T *p = malloc(sizeof(struct T) + 100); p->len = 100; strcpy(p->s, "hello world"); 構造体がメモリに配置される方法により、必要なブロックよりも大きい構造体に構造体をオーバーレイし、最後のメンバーを1 char指定されたものよりも大きいかのように扱うことができます。 だから問題は:この技術は技術的に未定義の動作ですか?。私はそれがそうであると期待しますが、標準がこれについて何を言っているのか興味がありました。 PS:私はこれに対するC99のアプローチを知っています。具体的には、上記のトリックのバージョンに忠実に答えてほしいと思います。

2
C ++ 20までのint未定義の動作にmallocを使用しています
次のコードはC ++ 20まで未定義の動作をしていると言われました。 int *p = (int*)malloc(sizeof(int)); *p = 10; 本当? 引数は、intオブジェクトに値を割り当てる前にオブジェクトの存続期間が開始されないというものでした(P0593R6)。問題を解決するには、配置newを使用する必要があります。 int *p = (int*)malloc(sizeof(int)); new (p) int; *p = 10; オブジェクトの存続期間を開始するために、簡単なデフォルトのコンストラクターを呼び出す必要が本当にありますか? 同時に、コードは純粋なCで未定義の動作をしません。しかし、intCコードでを割り当て、それをC ++コードで使用するとどうなりますか? // C source code: int *alloc_int(void) { int *p = (int*)malloc(sizeof(int)); *p = 10; return p; } // C++ source code: extern "C" int *alloc_int(void); …


8
動作が未定義のブランチは到達不能と見なされ、デッドコードとして最適化されますか?
次のステートメントを検討してください。 *((char*)NULL) = 0; //undefined behavior 明らかに未定義の動作を引き起こします。特定のプログラムにそのようなステートメントが存在するということは、プログラム全体が未定義であること、または制御フローがこのステートメントにヒットしたときにのみ動作が未定義になることを意味しますか? 次のプログラムは、ユーザーが番号を入力しない場合に備えて明確に定義されています3か? while (true) { int num = ReadNumberFromConsole(); if (num == 3) *((char*)NULL) = 0; //undefined behavior } それとも、ユーザーが何を入力しても、完全に未定義の動作ですか? また、コンパイラは、未定義の動作が実行時に実行されないことを想定できますか?これにより、時間を遡って推論することができます。 int num = ReadNumberFromConsole(); if (num == 3) { PrintToConsole(num); *((char*)NULL) = 0; //undefined behavior } ここで、コンパイラーは、num == 3未定義の動作を常に呼び出す場合に備えて推論することができます。したがって、このケースは不可能でなければならず、番号を印刷する必要はありません。ifステートメント全体を最適化することができます。この種の後方推論は規格に従って許可されていますか?

10
なぜprintf(“%f”、0); 未定義の動作を与える?
ステートメント printf("%f\n",0.0f); 0を出力します。 ただし、ステートメント printf("%f\n",0); ランダムな値を出力します。 ある種の未定義の動作を示していることに気づきましたが、具体的にその理由を理解できません。 全てのビットが0である、浮動小数点の値がまだ有効であるfloat0の値を持つ floatとint(つまりも関連している場合)、私のマシン上で同じサイズです。 なぜ浮動小数点リテラルの代わりに整数リテラルを使用すると、printfこの動作が発生するのですか? PS私が使用した場合と同じ動作が見られます int i = 0; printf("%f\n", i);

12
ループのどの時点で整数オーバーフローは未定義の動作になりますか?
これは、ここに投稿できないはるかに複雑なコードを含む私の質問を説明するための例です。 #include <stdio.h> int main() { int a = 0; for (int i = 0; i < 3; i++) { printf("Hello\n"); a = a + 1000000000; } } このプログラムにはa、3番目のループでオーバーフローするため、プラットフォームでの未定義の動作が含まれています。 それにより、プログラム全体の動作が未定義になりますか、それともオーバーフローが実際に発生したですか?コンパイラは、潜在的にそれが出て仕事ができるa だろう、それは未定義ループ全体を宣言し、彼らはすべてのオーバーフローが起こる前にもかかわらず、printfを実行する気にすることはできませんので、オーバーフロー? (CとC ++のタグは異なりますが、両方の言語が異なる場合は回答に興味があるためです。)

4
未定義の動作を含むソースコードがコンパイラをクラッシュさせることは合法ですか?
未定義の振る舞いを呼び出す、不十分に記述されたC ++ソースコードをコンパイルしようとすると、(彼らが言うように)「何でも起こり得る」としましょう。 C ++言語仕様が「準拠」コンパイラで許容できると見なすものの観点から、このシナリオの「すべて」には、コンパイラのクラッシュ(またはパスワードの盗用、またはコンパイル時の誤動作やエラーアウト)が含まれますか。未定義の振る舞いの範囲は、結果の実行可能ファイルが実行されたときに何が起こり得るかに特に限定されていますか?

5
未定義の動作とシーケンスポイントがリロードされました
このトピックを次のトピックの続編と考えてください。 前の記事 未定義の動作とシーケンスポイント この面白くて複雑な表現をもう一度見てみましょう(イタリック体のフレーズは上記のトピック* smile *から取られています): i += ++i; これは未定義の振る舞いを引き起こすと言います。これを言うとき、私たちは暗黙のうちにタイプが組み込みタイプのi1つであると仮定していると思います。 の型がiユーザー定義型の場合はどうなりますか?そのタイプはIndex、この投稿の後半で定義されていると言います(以下を参照)。それでも未定義の振る舞いを呼び出しますか? はいの場合、なぜですか?それは書くことと同等ではありませんi.operator+=(i.operator++());か、あるいは構文的に単純 i.add(i.inc());ですか?または、それらも未定義の振る舞いを呼び出しますか? いいえの場合、なぜですか?結局のところ、オブジェクトiは連続するシーケンスポイント間で2回変更されます。経験則を思い出してください。式は、連続する「シーケンスポイント間でオブジェクトの値を1回だけ変更できます。また、i += ++iが式の場合 、undefined-behaviorを呼び出す必要があります。その場合、同等のものi.operator+=(i.operator++());で i.add(i.inc());あり、undefined-behaviorも呼び出す必要があります。真実ではないようです!(私が理解している限り) または、i += ++iそもそも表現ではないですか?もしそうなら、それは何ですか、そして表現の定義は何ですか? それが式であると同時に、その動作も明確に定義されている場合、式に関連付けられているシーケンスポイントの数は、式に含まれるオペランドのタイプに何らかの形で依存することを意味します。私は(部分的にでも)正しいですか? ちなみに、この表現はどうですか? //Consider two cases: //1. If a is an array of a built-in type //2. If a is user-defined type which overloads the subscript operator! a[++i] = i; …

3
符号付き整数オーバーフローはC ++でも未定義の動作ですか?
ご存知のように、符号付き整数オーバーフローは未定義の動作です。しかし、C ++ 11のcstdintドキュメントには興味深いものがあります。 幅がそれぞれ正確に8、16、32、64ビットで、パディングビットがなく、負の値に2の補数を使用する符号付き整数型(実装が型を直接サポートしている場合にのみ提供) リンクを見る そして、ここに私の質問があります:標準では、、、および負の数は2の補数であると明示的に述べられているint8_tのでint16_t、これらのタイプのオーバーフローは未定義の動作ですか?int32_tint64_t 編集私はC ++ 11とC11標準をチェックしました、そしてここに私が見つけたものがあります: C ++ 11、§18.4.1: ヘッダーは、C標準の7.20と同じように、すべての関数、タイプ、およびマクロを定義します。 C11、§7.20.1.1: typedef名はintN_t、幅N、パディングビットなし、2の補数表現の符号付き整数型を指定します。したがって、int8_tは、正確に8ビットの幅を持つそのような符号付き整数型を示します。

4
オンラインIDEで奇妙な動作をするプログラム
私は以下のC ++プログラム(ソース)に出くわしました: #include <iostream> int main() { for (int i = 0; i < 300; i++) std::cout << i << " " << i * 12345678 << std::endl; } それは単純なプログラムのように見え、私のローカルマシンで正しい出力を提供します。 0 0 1 12345678 2 24691356 ... 297 -628300930 298 -615955252 299 -603609574 ただし、codechefなどのオンラインIDEでは、次の出力が得られます。 0 0 1 12345678 2 24691356 …

7
(なぜ)初期化されていない変数の未定義の動作を使用していますか?
私が持っている場合: unsigned int x; x -= x; この式の後でゼロになるx はずであることは明らかですが、私が見るところはどこでも、このコードの動作はx(減算の前まで)の値だけでなく、未定義であると言われています。 2つの質問: このコードの動作は本当に未定義ですか? (たとえば、準拠システムでコードがクラッシュする可能性がありますか?) もしそうなら、ここでゼロであるべきであることが完全に明らかであるのに、なぜCは動作が未定義でxあると言うのですか? つまり、ここで動作を定義しないことによって得られる利点は何ですか? 明らかに、コンパイラは、単に使用できるものは何でもそれは、変数内の「便利」とみなし、それが意図したとおりに動作します...そのアプローチと間違って何ガベージ値はありますか?

12
C / C ++での署名付きオーバーフローの検出
一見すると、この質問は整数オーバーフローを検出する方法の複製のように見えるかもしれません。ただし、実際には大幅に異なります。 符号なし整数オーバーフローの検出は非常に簡単ですが、C / C ++での符号付きオーバーフローの検出は実際にはほとんどの人が考えるよりも難しいことがわかりました。 それを行う最も明白でありながら素朴な方法は、次のようになります。 int add(int lhs, int rhs) { int sum = lhs + rhs; if ((lhs >= 0 && sum < rhs) || (lhs < 0 && sum > rhs)) { /* an overflow has occurred */ abort(); } return sum; } これに伴う問題は、C標準によれば、符号付き整数オーバーフローは 未定義の動作であるということです。 言い換えると、標準によれば、符号付きオーバーフローが発生するとすぐに、プログラムはnullポインターを逆参照した場合と同じように無効になります。したがって、上記の事後条件チェックの例のように、未定義の動作を引き起こして、事後にオーバーフローを検出しようとすることはできません。 上記のチェックは多くのコンパイラで機能する可能性がありますが、信頼することはできません。実際、C標準では符号付き整数オーバーフローは未定義であるとされているため、一部のコンパイラ(GCCなど)は上記のチェックを最適化します。、最適化フラグが設定されると、符号付きオーバーフローは不可能であると想定するため、を最適化します。これにより、オーバーフローをチェックする試みが完全に中断されます。 …

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