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

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


10
C ++での符号付きオーバーフローと未定義の動作(UB)
次のようなコードの使用について疑問に思っています int result = 0; int factor = 1; for (...) { result = ... factor *= 10; } return result; ループが何n度も繰り返される場合はfactor、10正確にn回数が掛けられます。ただし、合計回数をfactor掛けて使用します。ループの最後の反復以外はオーバーフローしないが、ループの最後の反復ではオーバーフローする可能性があると想定する場合、そのようなコードは受け入れ可能ですか?この場合、オーバーフローが発生した後、の値が使用されることはありません。10n-1factorfactor このようなコードが受け入れられるべきかどうかについて私は議論しています。ループがオーバーフローする可能性がある場合、乗算をifステートメント内に配置し、ループの最後の反復で乗算を実行しないことが可能です。欠点は、コードが煩雑になり、以前のすべてのループ反復をチェックする必要がある不要なブランチが追加されることです。また、ループの反復回数を1回減らし、ループの後にループ本体を1回複製することもできます。これもコードを複雑にします。 問題の実際のコードは、リアルタイムグラフィックスアプリケーションの総CPU時間の大部分を消費するタイトな内部ループで使用されます。

3
サイズ0の動的配列へのポインタの増分は未定義ですか?
AFAIK、ただし、サイズが0の静的メモリ配列を作成することはできませんが、動的配列を使用して作成できます。 int a[0]{}; // Compile-time error int* p = new int[0]; // Is well-defined 私が読んだpように、1つの最後の要素のように動作します。p指すアドレスを印刷できます。 if(p) cout << p << endl; イテレータ(最後の要素)ではできないので、そのポインタ(最後の要素)を逆参照できないことは確かですが、そのポインタをインクリメントするかどうかはわかりませんp。イテレータのような未定義の動作(UB)ですか? p++; // UB?

7
Cでポインター比較はどのように機能しますか?同じ配列を指さないポインターを比較しても大丈夫ですか?
K&R(Cプログラミング言語第2版)の第5章で以下を読みました。 まず、特定の状況下でポインタを比較できます。もしpとq同じ配列のメンバーへのポイント、その後のような関係==、!=、<、>=、などの作業を適切に。 これは、同じ配列を指すポインターのみを比較できることを意味しているようです。 しかし、私がこのコードを試したとき char t = 't'; char *pt = &t; char x = 'x'; char *px = &x; printf("%d\n", pt > px); 1 画面に出力されます。 まず第一に、私はので、私は、未定義またはいくつかのタイプやエラーになるだろうと思ったptし、px(少なくとも私の理解では)同じ配列を指していません。 またpt > px、両方のポインタがスタックに格納されている変数を指しているため、スタックtが大きくなり、メモリアドレスがx?どちらがpt > px本当ですか? mallocが導入されると、さらに混乱します。また、8.7章のK&Rには、次のように書かれています。 ただし、によって返されるさまざまなブロックへのポインターをsbrk有意義に比較できるという前提はまだ1つあります。これは、配列内でのみポインタ比較を許可する標準では保証されていません。したがって、このバージョンのmallocは、一般的なポインタ比較が意味のあるマシン間でのみ移植可能です。 ヒープでmallocされたスペースを指すポインターとスタック変数を指すポインターを比較しても問題はありませんでした。 たとえば、次のコードは正常に機能し1、印刷されました。 char t = 't'; char *pt = &t; char *px = malloc(10); strcpy(px, pt); …

2
std :: vectorに追加するときのクラスフィールドの奇妙な動作
次の状況で、(clangおよびGCCで)非常に奇妙な動作が見つかりました。nodesクラスのインスタンスである1つの要素を持つベクトルがありますNode。次に、ベクターにnodes[0]新しい関数を追加する関数を呼び出しますNode。新しいノードが追加されると、呼び出し元オブジェクトのフィールドがリセットされます!ただし、関数が終了すると、通常の状態に戻ります。 これは最小限の再現可能な例だと思います: #include <iostream> #include <vector> using namespace std; struct Node; vector<Node> nodes; struct Node{ int X; void set(){ X = 3; cout << "Before, X = " << X << endl; nodes.push_back(Node()); cout << "After, X = " << X << endl; } }; int main() { nodes = …

4
初期化されていないメンバーを持つ構造体をコピーする
一部のメンバーが初期化されていない構造体をコピーすることは有効ですか? 未定義の動作ではないかと思いますが、その場合、初期化されていないメンバーを構造体に残すと(それらのメンバーが直接使用されない場合でも)、非常に危険になります。だから、規格にそれを許すものがあるのか​​しら。 たとえば、これは有効ですか? struct Data { int a, b; }; int main() { Data data; data.a = 5; Data data2 = data; }

3
CにはC ++のstd :: lessと同等のものがありますか?
私は最近やっての未定義の動作に質問に答えるたp < qときCにpし、q異なるオブジェクト/配列へのポインタです。それは私に考えさせました:C ++は<この場合と同じ(未定義)動作を持っていますが、ポインターが比較できる場合std::lessと同じものを返すことが保証され<、できない場合は一貫した順序を返す標準ライブラリテンプレートも提供します。 Cは、(同じ型への)任意のポインタを安全に比較できるようにする同様の機能を持つものを提供していますか?C11標準を調べても何も見つかりませんでしたが、Cでの経験はC ++よりも桁違いに小さいため、簡単に何かを見落としていた可能性があります。

1
consteval関数が未定義の動作を許可するのはなぜですか?
C ++には定数式の非常にきちんとした特性があります。それらの評価に未定義の動作を含めることはできません(7.7.4.7): 抽象マシン([intro.execution])の規則に従ってeの評価が次のいずれかを評価しない限り、式eはコア定数式です。 ... このドキュメントの[intro]から[cpp]で指定されている未定義の動作を持つ操作[注:たとえば、符号付き整数オーバーフロー([expr.prop])、特定のポインター演算([expr.add])、ゼロによる除算、または特定のシフト演算—後記]; 値を格納しようとする13!中でconstexpr int実際には、素敵なコンパイルエラーを生成します: constexpr int f(int n) { int r = n--; for (; n > 1; --n) r *= n; return r; } int main() { constexpr int x = f(13); return x; } 出力: 9:19: error: constexpr variable 'x' must be initialized by a …

2
有効なC ++プログラムを終了しないプログラムですか?
プログラムを終了する必要がありますか?言い換えれば、技術的に未定義の動作を永久に実行するプログラムですか?これは空のループについてではないことに注意してください。「もの」(つまり、観察可能な動作)を永遠に行うプログラムについて話す。 たとえば、次のようなもの: int main() { while (true) { try { get_input(); // calls IO process(); put_output(); // calls IO, has observable behavior // never break, exit, terminate, etc } catch(...) { // ignore all exceptions // don't (re)throw // never go out of loop } } } 経験的にすべての正気なコンパイラは、上記の種類のプログラムに対して期待されるコードを生成するため(これは他のUBのソースがないことを前提としています)、これはより学術的な質問です。そしてもちろん、終了しないプログラム(OS、埋め込み、サーバー)はたくさんあります。しかし、標準は時々風変わりなので、質問です。 接線:「アルゴリズム」の多くの(一部の?)定義では、アルゴリズムを終了する必要があります。つまり、終了しない一連の操作はアルゴリズムとは見なされません。 接線。停止問題は、任意のプログラムが入力に対して終了するかどうかを判別するアルゴリズムが存在できないことを示しています。ただし、この特定のプログラムの場合、メインから抜け出す原因となる分岐がないため、コンパイラーはプログラムが終了しないことを容易に判別できます。質問は言語弁護士なので、これは無関係です。

3
非constへのポインターと同じアドレスのconst引数へのポインターを使用した関数呼び出し
データの配列を入力し、ポインターを使用して別のデータの配列を出力する関数を書きたいのですが。 コンパイラがconstを最適化できることを知っているので、両方が同じアドレスsrcをdst指している場合、結果はどうなのかと思います。未定義の動作ですか?(CとC ++の両方にタグを付けました。これは、答えが異なるかどうかわからないためです。両方について知りたいのです。) void f(const char *src, char *dst) { dst[2] = src[0]; dst[1] = src[1]; dst[0] = src[2]; } int main() { char s[] = "123"; f(s,s); printf("%s\n", s); return 0; } 上記の質問に加えてconst、元のコードでを削除すると、これは明確になりますか?

1
プリミティブstatic_vector実装での未定義の動作の可能性
tl; dr:static_vectorの動作が未定義だと思いますが、見つかりません。 この問題はMicrosoft Visual C ++ 17にあります。この単純で未完成のstatic_vectorの実装、つまりスタック割り当て可能な固定容量のベクターがあります。これは、std :: aligned_storageとstd :: launderを使用するC ++ 17プログラムです。私はそれを問題に関連すると思われる部分にまで煮詰めようとしました: template <typename T, size_t NCapacity> class static_vector { public: typedef typename std::remove_cv<T>::type value_type; typedef size_t size_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; static_vector() noexcept : count() { } ~static_vector() …

1
`string.assign(string.data()、5)`は明確に定義されていますか、それともUBですか?
同僚はこれを書きたかった: std::string_view strip_whitespace(std::string_view sv); std::string line = "hello "; line = strip_whitespace(line); 戻るstring_viewと私はアプリオリに不安になり、さらにここでのエイリアシングはUBのように見えました。 line = strip_whitespace(line)この場合、と同等であると確信できますline = std::string_view(line.data(), 5)。私はそれが呼び出すと信じてstring::operator=(const T&) [with T=string_view]と同等になるように定義されている、line.assign(const T&) [with T=string_view]と等価になるように定義され、line.assign(line.data(), 5)これを実行するために定義されています: Preconditions: [s, s + n) is a valid range. Effects: Replaces the string controlled by *this with a copy of the range [s, s …


2
未定義のC ++の動作がCの定義された動作と一致するとどうなりますか?
*.cpp(Cコンパイラではなく)C ++でコンパイルするファイルがあります。含まれている関数は、Cで定義されているように見えるキャスト(最後の行を参照)に依存していますが(間違っている場合は修正してください!)、この特別な型のC ++ではありません。 [...] C++ code [...] struct sockaddr_in sa = {0}; int sockfd = ...; sa.sin_family = AF_INET; sa.sin_port = htons(port); bind(sockfd, (struct sockaddr *)&sa, sizeof sa); [...] C++ code [...] これをC ++ファイルでコンパイルしたので、これは現在定義済みまたは未定義の動作ですか?または*.c、これをファイルに移動して、動作を定義する必要がありますか?

1
GCCが不正なconstexprラムダ呼び出しを報告できない
以下は、IIFE(Immediately Called Lambda-Axpression)として表される未定義の動作の2つのテストケースです。 constexpr auto test3 = []{ int* p{}; { int x{}; p = &x; } return *p; // Undefined Behaviour }(); // IIFE constexpr auto test4 = []{ int x = std::numeric_limits<int>::min(); int y = -x; // Undefined Behaviour return y; }(); int main() {} GCCトランクでコンパイルすると、test4で未定義の動作を示すため、正しく拒否されconstexprます。一方、test3受け入れられます。 GCCは受け入れる権利がありますtest3か?

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