2016-08-26 12 views
4

私は最近、C++プログラミングに慣れてきており、コンパイルされたバージョンの 'debug vs release'全体を実行し続けています。コンパイルされたコードのリリース版とデバッグ版の違いをかなりよく理解しているように感じました。デバッグバージョンのコードでは、コンパイラはデバッガを実行してプログラムを1行ずつステップ実行できるように、コードを最適化しようとしません。本質的に、コンパイルされたコードは、ソースコードの実行方法と密接に似ています。リリースモードでコンパイルするとき、コンパイラはプログラムの最適化を試みて、同じ機能を持つようにしますが、より効率的です。リリースとデバッグのコンパイル済みプログラムのソースコードに違いはありますか? [C/C++]

しかし、私は、リリースとデバッグバージョンの間のソースコードが異なる可能性があるかどうかについて興味があります。つまり、debug vs releaseを参照するとき、コンパイルされたコードについて話しているのでしょうか、ソースコードに違いがあるのでしょうか?

この質問は、正式なステップバイステップデバッガが存在しないにもかかわらず、シリアルモニタが存在する独自のプログラミング言語で作業しているために発生します。このように「リリース」コード対たちの「デバッグ」の多くは、このようなものに見えるの#defineを経由して実装されています。だからあなたのIDEに応じて、私の質問を要約する

#ifdef _DEBUG 

    check that error didn't occur... 

    SerialPrint("Error occurred") 

#endif 

を、多くの場合、どのようなIを実現するためにそこに設定されていますイラストをしましたか?つまり、デバッグバージョンにコンパイルしようとすると、ソースコードの変更と統合できますか?あるいは、リリース対デバッグは、通常、コンパイルされたバイナリを参照するだけですか?

ありがとうございました!

+2

多くの場合、他のマクロで囲まれたシーケンスとよく似ています。実際には、C++標準に指定されているようなものがあります。['assert'](http://en.cppreference.com/w/cpp/error/assert) –

+2

たとえば、Microsoft Visual C++の標準ライブラリをコンパイルするとデバッグモードでは、コンテナ( 'std :: vector'など)とイテレータの拡張データ構造を使用してeにします。 g。無効化されたイテレータを使用して検出を支援します。 – ach

答えて

4

リリースとデバッグのコンパイル済みプログラムのソースコードに違いはありますか?

ソースコードと、ライブラリまたはプログラムをコンパイルするためのオプションによって異なります。以下は私が知っているいくつかの違いです。

"デバッグおよび診断" の最も単純なassertある

をアサートします。これらは、NDEBUGでないときに有効です。が定義されています。アサーションは自己デバッグコードを作成し、予期しない条件に遭遇したときにスナップします。トリックはすべてを主張しなければならないということです。パラメータと状態を検証するたびに、アサートが表示されます。どこでもアサーションがある場合は、ifを参照して、パラメータと状態を検証してください。

アサートのないコードベースが表示されたら笑います。私は自分自身に言いますが、開発者はデバッガの下でそれを無駄にしていると手に余りにも多くの時間を持っています。私はしばしばあなたが主張を使わない理由を尋ねます。彼らは通常次のように答えます。

Posix assertは電話をしていますのでabortを呼び出します。プログラムをデバッグしている場合は、通常、コードをステップ実行して、assertの原因となった負の条件をコードがどのように処理するかを確認します。プログラムの終了は "デバッグと診断"の目的で失敗します。それは、C/C++の歴史の中で最悪の決定でなければなりません。誰もが中止の理由を思い出してはいないようです(数年前、私はさまざまなC/C++標準リストの系図を追跡しようとしました)。

通常、無効なPosixアサーションは、assertのように、LinuxではSIGTRAP、WindowsではDebugBreakが呼び出されます。例えば、のサンプルを参照してください。 Posix assertをあなたのアサートに置き換えて、使用しているライブラリが更新された動作を得るようにします(既にコンパイルされている場合は遅すぎます)。

ISCのBIND(インターネットに動力を与えるDNSサーバ)のようなプロジェクトでは、DoS自体がアサーションを持っています(彼ら自身のアサーションがあり、Posixアサートを使用しません)。自発的なDoSのためにBINDに対していくつかのCVEがあります。自分でDoSするのは、 "デバッグ中のプログラムを中断させる"ことです。

完全性のために、Microsoft Foundation Classs(MFC)は以前は間違いを早期に発見するために16,000または20,000のアサーションを使用していましたが、それは1990年代後半か2000年代半ばに戻った。私は今日の状態ではありません。

のAPI

一部のAPI意図的"デバッグおよび診断"のために構築されているものが存在します。他のAPIも、本番環境で必ずしも安全に使用することはできませんが、そのために使用できます。

(意図的に作成された)前者の例は、LoggingとDebugPrint APIです。 Appleはそれを使って、ユーザーのFileVaultパスワードとキーを出力することに成功しました。またos x filevault debug printを参照してください。

後者(生産には安全でない)の例は、Windows IsBadReadPointerIsBadWritePointerです。それは競争状態に苦しんでいるため、生産上安全ではありません。しかし、あなたは特別な精査をしたいので、通常は開発のためにうまくいく。

セキュリティレビューと監査を実行する際には、必須ではないすべてのログを削除するよう尋ねたり、推奨することがよくあります。実行時にロギング・レベルを変更できないようにしてください。アプリが制作になると、デバッグの時間が終了します。すべてを記録する理由はありません。

ライブラリ

時には診断のデバッグを支援するために使用する特別なライブラリがあります。 LinuxのElectric FenceとMicrosoftのCRT Libraryがあります。どちらもAPIを備えたメモリチェッカです。この場合、リンクするコマンドも異なります。

オプション

時々、デバッグおよび診断を支援するために、追加のオプションや定義を必要としています。 GlibC++と-D_GLIBCXX_DEBUGが気になります。もう1つはコンセプトチェックです。これは以前は-D_GLIBCXX_CONCEPT_CHECKSの定義で有効になっていました。そのブーストコードとその壊れたので、あなたはそれを使用すべきではありません。このような場合、コンパイルフラグは異なります。

私がよく笑うもう1つは、NDEBUGが定義されていないリリースビルドです。これにはDebianとUbuntuがポリシーの問題として含まれています。 NSA、GHCQなどの3文字代理店は、機密情報(サーバーキーなど)を取得し、暗号化を取り除いて(保護されていないファイルに書き込む)、機密情報を出力してくれてありがとうレポートなど)。値が明示的に初期化されていないとき

初期

いくつかの開発環境では、特別なビットパターンで初期化を行います。コンパイラやリンカのようなツールの本当の機能です。 Microsoftのツールが思い浮かぶ。 When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?を参照してください。GCCには機能要求がありましたが、これまで何も完了していないと思います。

私は、プロダクションDLLを逆アセンブルして、デバッグDLLを出荷していることを知っているので、私が頻繁に笑います。リリースDLLには、開発チームがクリアできなかったメモリエラーがあることがよくあるので、私は笑います。 Adobeはこれを行うことで有名である(AppleやMicrosoftのようなオペレーティングシステムを提供していないにもかかわらず、Adobe supplies some of the most insecure software on the planet)。


#ifdef _DEBUG 

    check that error didn't occur... 

    SerialPrint("Error occurred") 

#endif 

それは私が泣きたくなる、あなたはまだ2016年GDBでこれを行う必要がある(だった?)あなたがprintfの年代を使用する必要がありますので、Aarch64、X32およびS/390の下で壊れましたコードをデバッグします。

0

C++標準では、the assert macroによるデバッグとリリースの種類がサポートされています。その動作は、NDEBUGマクロシンボルが定義されているかどうかによって制御されます。しかし、これはアプリケーション全体の設定として意図されていません。標準では、<assert.h>または<cassert>の各時刻が含まれており、何回含まれているかにかかわらず、現在の定義状態NDEBUGに従って有効な定義assertが変更されることが明示的に記載されています。

コンパイラベンダーの標準ライブラリの実装は、他のシンボルに依存する場合があります。

そして、アプリケーションフレームワークは、さらに他のシンボルに依存することがあります。 _DEBUGは、(デバッグライブラリ)/MTdまたは/MDdオプションを指定すると、Visual C++コンパイラによって定義されたシンボルです。

0

IDEの設定に関しては、自由に行うことができます。はい、いくつかのIDE(MS Visual Studioなど)やCMakeのようなツールでは、デバッグ設定用にマクロ定義を追加しますが、欠落している場合は自分で定義することもできます。また、_DEBUGの名前が石で設定されていない場合は、代わりにMY_PROJECT_DEBUGなどを定義できます。

リリースとデバッグバージョンの主な機能が同じであれば問題ありません。プログラムによって生成された最終結果が同じである限り、#ifdef _DEBUG(またはそれ以外の場合は#ifndef _DEBUG)にラップされたコードを追加できます。

オプションであると考えられるデバッグコードが副作用を引き起こす場合、通常の間違いがあります。他の人によって与えられた例を考えてみましょう。おおよその実装は次のようになります。リリースモードで(NDEBUGのみリリースモードで定義されていることを提供する)ときassertxを評価しませんか

#ifdef NDEBUG 
    #define assert(x) ((void)0) 
#else 
    #define assert(x) ((x) ? (void)0 : abort()) 
#endif 

注意してください。

#include <assert.h> 

int main() 
{ 
    int x = 5; 
    assert(x-- == 5); 
    return x; // returns 5 in release mode, 4 in debug mode 
} 

上記の行動はあなたが望むものではありません、それは最終結果を変更するよう:これはマクロの引数は副作用を持っているなどの条件が渡された場合、あなたのコードがモードをデバッグで異なる動作をし、リリースすることを意味します。現実のコードは、より複雑であり、副作用を導入するためにはあまり明白でないかもしれない。 assert(SomeFunctionCall())などが挙げられる。

リリースビルドでも有効にしたい人もいるかもしれないが、アサーションは最良の例ではないかもしれないことに注意してください。

関連する問題