2

This question might make no sense, but I'll ask anyway with an example. Does this code exhibit undefined behaviour?

int main() {
    int a, b; // uninitialised

    memcpy(&a, &b, sizeof(int));
}

I would usually say yes, because causing an lvalue-to-rvalue conversion of an uninitialised object is UB, something which must be done to copy the bytes of b to a.

However, memcpy may or may not be implemented in C++. If memcpy is written in assembly for example, then there are no such rules. Do programs that do things that would normally cause undefined behaviour still cause it if they outsource the offending operations to other languages with dissimilar rules?

4

5 に答える 5

2

あなたが説明する場合a、C ++プログラムによって割り当てられ、に渡されmemcpy()ます。これは、動作がまだ定義されていないことを意味します。

ただし、これは、動作がランダムである、または実行間で変化することを意味するものではありません。Undefinedは、動作が定義されていないことを意味します。つまり、プログラムの中断など、特定の動作に依存することはできません。CまたはC++でデバッグするのが最も難しい問題のいくつかは、コンパイラーが未定義の構成を期待どおりに機能するものに変換する場合です。その後、コンパイラフラグを変更すると、突然動作が停止します。

于 2013-02-06T21:56:15.133 に答える
2

これは、「C ++では、ステーキを過度に焦がすと未定義動作が発生しますか?」と尋ねるようなものです。

すべての未定義動作とは、C ++(またはCなど)標準が、プログラムの変換および/または実行時に何が起こるかを保証しないことを意味します。当然のことながら、C ++標準は、他の言語の関数についてはほとんど何も述べていません。

やや関連性のある引用は7.4からのものだけです

asm宣言は条件付きでサポートされています。その意味は実装定義です。

そして7.5から

[リンケージ仕様の構文で...]この国際標準は、文字列リテラル "C"とのセマンティクスを指定します"C++"。実装定義のセマンティクスで、または条件付きでサポートされている以外の文字列リテラルの使用。"C""C++"

したがって、基本的には、C ++と一緒に他の言語を使用することも可能かもしれませんが、このドキュメントでは、ピースを接着するために必要な構文以外については説明しません。

C ++標準の観点からは、他の言語の関数は、C++プログラムに対して実装定義の効果をもたらします。実装定義は、移植性はありませんが、通常、未定義動作よりも優れていると見なされます。ただし、C ++とC以外のものを使用しても、必ずしもすべてのC++実装に移植できるとは限らないことは驚くべきことではありません。

于 2013-02-06T23:45:55.690 に答える
1

UBは言語固有の「もの」ではありません。それは「あなたがしていることには明確な振る舞いがない」ということです。したがって、「初期化されていないメモリの使用が定義されていない」理由は、言語Cが、書き込まれていないメモリを読み取った場合にどうなるかを規定できないためです。別の回答で説明されているように、メモリが初期化されていない場合、最初の書き込みでパリティビットが正しく設定されるため、パリティエラーまたはECCエラーが発生する可能性があります。メモリに「電源投入時に発生したもの」が含まれている場合、パリティ/ecc値が間違っている可能性があります。

ECCまたはパリティエラーは、メモリの不良が予想されないため、システムの停止につながることがよくあります。

したがって、重要なのは、実行するコードがどの言語で記述されているかではなく、「初期化されていないメモリから読み取った場合の動作がうまくいかない可能性がある」ということです。コードがC、C ++、アセンブラ、Pascal、Fortran、LisPのいずれで記述されているかに関係なく、メモリを読み取る動作。

また、未定義は必ずしも「悪いことが起こる」ということではなく、「仕様は結果が何であるかを説明しておらず、UBで悪いことが起こることが許されている」ということを覚えておいてください。ゼロで除算すると、プログラムがクラッシュすることは保証されません。おそらくクラッシュしますが、反対側でフィードしたのと同じ値が返される場合もあります/。これは、完全に有効なUBです。初期化されていないメモリを読み取ると、「ゼロになる」、「すべて1になる」、「1と0が混在している、どちらかわからない」、「メモリエラーが疑われるためにシステムが再起動する可能性がある」という結果になる可能性があります。 "。そしてもちろん、それは毎回同じではないかもしれません-たとえば、パリティビットが「正しい」場合もあれば、そうでない場合もあります。

明確にするために:私はCまたはC++標準のすべてのセクションのすべての段落を知っている人の一人ではありません。私は生計を立てるためのコードを書いていますが、プロセッサと接続されたハードウェアが、仕様に「未定義の動作である...」と書かれている理由を理解するのに十分な知識があります。 t 2人目の人を使用する]-初期化されていない変数を使用する場合、C言語は特定の動作を強制しようとしません。これは、プラットフォームが特定のプラットフォームでの使用を制限する可能性があるためです。動作を保証するものではありません[動作を指定すると、遅かれ早かれ誰かがその動作に依存するため、すべてのプラットフォームに実装する必要があります]。

于 2013-02-06T22:02:53.443 に答える
1

実装は言語を自由に拡張でき、定義された動作をCの未定義の動作に与えます。自動保存期間(CではUB)を使用して初期化されていないオブジェクトを読み取る例では、その値は指定されていないと言えますが、オブジェクトを評価しても未定義の動作は呼び出されません。

C89およびC99の理論的根拠では、C委員会は次のように述べています。

未定義の動作は、診断が難しい特定のプログラムエラーをキャッチしないように実装者にライセンスを与えます。また、準拠する可能性のある言語拡張の領域を識別します。実装者は、公式に定義されていない動作の定義を提供することにより、言語を拡張できます。*

このようなプログラムは、この実装では有効なプログラムですが、それでも無効なCプログラムです。

于 2013-02-06T22:22:10.173 に答える
0

http://blog.regehr.org/archives/213これは私が提案することを指します。以下の定義について議論したい場合は、そちらで取り上げてください。IMO、これはあなたが求めていることの核心であり、ほとんどの答えは伝えようとしています。あなたは自由に反対することができます。

これらの#1と#2を考えてみましょう:

Type 1: Behavior is defined for all inputs 
Type 2: Behavior is defined for some inputs and undefined for others 
Type 3: Behavior is undefined for all inputs 

タイプ1は、関数がUBに入らないようにエラーと例外を発生させることを意味します。タイプ2は、コードがすべての可能なエラーと例外を発生させるわけではなく、UBに入る可能性があることを意味します。

重要なのは、文書化されたライブラリ呼び出しを使用しているということです。代わりにstrcpyまたはgetsの例を使用してみましょう。これらのライブラリ呼び出しに長い文字列とオーバーフローメモリをフィードして、UBを引き起こす可能性があることは一般的な知識のようです。これを止める可能性のある実装定義の制約がありますが、よく知っています。したがって、あなたの質問は実際には標準を書くことはほとんどありませんが、ライブラリ呼び出しのドキュメントが何を言っているか、そしてそれがタイプ1かタイプ2かについてのすべては、strcpy、gets、および他のライブラリ関数が明らかにタイプ2である可能性があります。ライブラリのユーザーへの警告です。私はタイプ2です。挑発されると爆発する可能性があります。

IMO、ライブラリアドオンは実装定義であるため、標準で処理する方法はありません。つまり、答えは次のとおりです。C++標準とは何の関係もありません。

于 2013-02-07T21:34:47.513 に答える