-Wall
の設定、および-std=XXX
の設定以外に、Cで使用するための本当に有用な、しかしあまり知られていないコンパイラフラグはありますか?
私は、追加の警告に特に興味があります。また、偶発的な型の不一致を完全に最小限に抑えるために、場合によっては警告をエラーに変換します。
いくつかの-f
コード生成オプションが興味深い:
-ftrapv
関数により、プログラムは符号付き整数オーバーフロー(Cの正式には「未定義の動作」)で中断します。
-fverbose-asm
は、-S
でコンパイルしてアセンブリの出力を調べる場合に役立ちます。有益なコメントが追加されます。
-finstrument-functions
は、すべての関数の入り口と出口でユーザー提供のプロファイリング関数を呼び出すコードを追加します。
ここに私のものがあります:
-Wextra
、-Wall
:必須。-Wfloat-equal
:通常、浮動小数点数が等しいかどうかをテストするのは悪いため便利です。-Wundef
:初期化されていない識別子が#if
ディレクティブで評価される場合に警告します。-Wshadow
:ローカル変数が別のローカル変数、パラメーター、またはグローバル変数をシャドウするとき、または組み込み関数がシャドウされるたびに警告します。-Wpointer-arith
:関数またはvoid
のサイズに依存するものがある場合に警告します。-Wcast-align
:ターゲットの必要なアライメントが増加するようにポインターがキャストされるたびに警告します。たとえば、整数が2バイトまたは4バイトの境界でのみアクセスできるマシンで、char *
がint *
にキャストされた場合に警告します。-Wstrict-prototypes
:引数の型を指定せずに関数が宣言または定義されている場合に警告します。-Wstrict-overflow=5
:符号付きオーバーフローが発生しないという仮定に基づいてコンパイラーが最適化する場合について警告します。 (値5は厳しすぎる可能性があります。マニュアルページを参照してください。)-Wwrite-strings
:文字列定数にconst char[
長さ]
型を指定して、1つのアドレスをconst char *
以外のポインターにコピーすると警告が表示されるようにします。-Waggregate-return
:構造体または共用体を返す関数が定義または呼び出された場合に警告します。-Wcast-qual
:ターゲット型から型修飾子を削除するためにポインターがキャストされるたびに警告します*。-Wswitch-default
:switch
ステートメントにdefault
ケースがない場合は常に警告する*。-Wswitch-enum
:switch
ステートメントに列挙型のインデックスがあり、その列挙の1つ以上の名前付きコードのcase
がない場合に警告する*。-Wconversion
:値を変更する可能性のある暗黙の変換について警告する*。-Wunreachable-code
:コードが実行されないことをコンパイラが検出した場合に警告する*。マークされたもの * 時には偽りの警告が多すぎるため、必要に応じてそれらを使用します。
常に-O
以上(-O1
、-O2
、-Os
など)を使用します。デフォルトの最適化レベルでは、gccはコンパイル速度を重視し、変数の初期化などについて警告するのに十分な分析を行いません。
コンパイルを停止しない警告は無視される傾向があるため、-Werror
ポリシーの作成を検討してください。
-Wall
は、エラーである可能性が非常に高い警告をオンにします。
-Wextra
に含まれる警告は、一般的で正当なコードにフラグを立てる傾向があります。これらはコードレビューには役立ちます(リントスタイルのプログラムではより多くの落とし穴がより柔軟になりますが)が、通常の開発ではそれらをオンにしません。
プロジェクトの開発者が浮動小数点に慣れていない場合は-Wfloat-equal
をお勧めします。
-Winit-self
は便利です。 -Wuninitialized
に含まれていないのはなぜだろうか。
-Wpointer-arith
は、-pedantic
で動作しないほとんどポータブルなコードがある場合に便利です。
-save-temps
これにより、プリプロセッサとアセンブリの結果が残ります。
前処理されたソースは、マクロのデバッグに役立ちます。
アセンブリは、どの最適化が有効になったかを判断するのに役立ちます。たとえば、GCCがいくつかの再帰関数で末尾呼び出しの最適化を行っていることを確認したい場合があります。これがないと、潜在的にスタックがオーバーフローする可能性があります。
-fmudflap-すべての危険なポインター操作にランタイムチェックを追加して、UBをキャッチします。これにより、プログラムは再びバッファオーバーフローを効果的に回避し、あらゆる種類のダングリングポインターをキャッチしやすくなります。
デモは次のとおりです。
$ cat mf.c
int main()
{
int a[10];
a[10]=1; // <-- o noes, line 4
}
$ gcc -fmudflap mf.c -lmudflap
$ ./a.out
*******
mudflap violation 1 (check/write): time=1280862302.170759 ptr=0x7fff96eb3d00 size=44
pc=0x7f3a575503c1 location=`mf.c:4:2 (main)'
/usr/lib/libmudflap.so.0(__mf_check+0x41) [0x7f3a575503c1]
./a.out(main+0x90) [0x400a54]
/lib/libc.so.6(__libc_start_main+0xfd) [0x7f3a571e2c4d]
Nearby object 1: checked region begins 0B into and ends 4B after
mudflap object 0xf9c560: name=`mf.c:3:6 (main) a'
bounds=[0x7fff96eb3d00,0x7fff96eb3d27] size=40 area=stack check=0r/3w liveness=3
alloc time=1280862302.170749 pc=0x7f3a57550cb1
number of nearby objects: 1
誰もまだこれを言っていないことに驚いています-私が懸念している限り、最も有用なフラグは-g
です。実行中のプログラムのstepi
コマンドのような、熟練したアセンブリの読み取り。
実際にはC/C++とは関係ありませんが、とにかく便利です:
@file
上記のすべての適切なフラグ(すべて指定済み)を「ファイル」に入れ、このフラグを使用して、そのファイル内のすべてのフラグを一緒に使用します。
例えば:
ファイル:compilerFlags
-壁
-std = c99
-ウェクストラ
次にコンパイルします:
gcc yourSourceFile @compilerFlags
-march=native
は、コンパイルするプラットフォーム(= chip)向けに最適化されたコードを生成します
コンパイラーによって事前定義されているプリプロセッサーフラグを知る必要がある場合:
echo | gcc -E -dM -
エラーの検出にはあまり役立ちませんが、めったに言及されない-masm=intel
オプションを使用すると、-S
を使用してアセンブリの出力をより適切に検査できます。
AT&T Assembly構文は頭を痛めすぎます。
私のメイクファイルには通常
CFLAGS= -Wall -Wextra -Weffc++ -Os -ggdb
...
g++ $(CFLAGS) -o junk $<
gcc $(CFLAGS) -o $@ $<
rm -f junk
これらのオプションの中で最も重要なものについては以前に説明したので、まだ指摘されていない2つの機能を指摘します。
まだがまともなC++コンパイラを持たないプラットフォームへの移植性のために必要をプレーンCにするコードベースに取り組んでいるにもかかわらず、「余分な」コンパイルを行いますC++コンパイラ(Cコンパイラに加えて)。これには3つの利点があります。
はい、私は絶望的に楽観的なポリアンナであり、1つのプラットフォームが廃止されたと宣言されるか、まともなC++コンパイラが得られるようになりました確かにと考え続け、最終的にC++に切り替えることができます。私の考えでは、それは避けられないことです。唯一の問題は、経営者が最終的に全員にポニーを発行する前か後に発生するかどうかです。 :-)
言及されていない素晴らしいフラグは次のとおりです。
-Werror-implicit-function-declaration
関数が宣言される前に使用されるたびにエラーを返します。
-Wstrict-prototypes -Wmissing-prototypes
man gcc
マニュアルには、適切な説明のある興味深いフラグがたくさんあります。ただし、-Wallはおそらくgccを可能な限り詳細にします。より興味深いデータが必要な場合は、valgrindまたはエラーをチェックする他のツールをご覧ください。
-M*
オプションのファミリー。
これらを使用すると、CまたはC++のソースファイルが依存するヘッダーファイルを自動的に把握するmakeファイルを作成できます。 GCCは、この依存情報を使用してmakeファイルを生成します。その後、プライマリmakeファイルからそれらをインクルードします。
次に、-MDおよび-MPを使用して、c ++ソースファイルとヘッダーファイルでいっぱいのディレクトリをコンパイルし、すべての依存関係を自動的に把握する、非常に汎用的なメイクファイルの例を示します。
CPPFLAGS += -MD -MP
SRC = $(wildcard *.cpp)
my_executable: $(SRC:%.cpp=%.o)
g++ $(LDFLAGS) -o $@ $^
-include $(SRC:%.cpp=%.d)
これについて詳しく説明しているブログ投稿は次のとおりです。 http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html
すべての警告をエラーとして扱い、コンパイルを停止する-Werror
があります。 gcc
マニュアルページ は、コンパイラのすべてのコマンドラインスイッチについて説明しています。
まあ、-Wextra
も標準でなければなりません。 -Werror
は、警告をエラーに変換します(特に-Wno-unused-result
なしでコンパイルする場合、非常に迷惑になる可能性があります)。 -pedantic
をstd=c89
と組み合わせて使用すると、C99機能を使用する場合に追加の警告が表示されます。
しかし、それはそれについてです。 Cコンパイラを、C自体よりも型が保存されたものにチューニングすることはできません。
-Wfloat-equal
From: http://mces.blogspot.com/2005/07/char-const-argv.html
私が気に入っている他の新しい警告の1つは、-Wfloat-equalです。等条件で浮動小数点数を持っているときはいつでもそれは警告します。それは素晴らしいです!すべてのコンピューターグラフィックスまたは(さらに悪いことに)計算幾何学アルゴリズムをプログラムしている場合、2つのフロートが同等に一致することはありません...
特定の問題を修正するためのフラグを探しているこのスレッドを見つけましたが、ここには表示されませんので、私を困惑させていたものを追加します my post :
-Wformat=2
フラグ
-Wformat
=>printf
およびscanf
などの呼び出しを確認して、指定された引数が指定されたフォーマット文字列に適したタイプであることを確認してください...
そして、それに関する本当に重要な部分( GCCマニュアルによる ):
-Wformat
は-Wall
に含まれています。フォーマットチェックのいくつかの側面をより詳細に制御するために、オプション-Wformat-y2k
、-Wno-format-extra-args
、-Wno-format-zero-length
、-Wformat-nonliteral
、-Wformat-security
、および-Wformat=2
を使用できます、ただし-Wallには含まれません。
したがって、-Wall
を持っているからといって、すべてを持っているわけではありません。 ;)
私は時々、はるかに小さい実行可能ファイルに-s
を使用します。
-s
Remove all symbol table and relocation information from the executable.
ソース: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options
私は特に追加の警告に興味があります。
-Wall
に加えて、-W
または-Wextra
オプション(-W
は新しいバージョンと同様に古いバージョンのgccでも動作します。最近のバージョンでは代替名-Wextra
は、同じことを意味しますが、より説明的です)、さまざまな追加の警告を有効にします。
また、これらのいずれかによって有効にされない警告がさらに多くあります。一般的に、より疑わしいものに対してです。使用可能なオプションのセットは、使用しているgccバージョンによって異なります-詳細についてはman gcc
またはinfo gcc
を参照するか、使用している特定のgccバージョンについて オンラインドキュメント を参照してください-pedantic
は、使用されている特定の標準(-std=xxx
や-ansi
などの他のオプションに依存)に必要なすべての警告を発行し、gcc拡張機能の使用について文句を言います。
および/または、場合によっては警告をエラーに変えて、偶発的な型の不一致を完全に最小限に抑えます。
-Werror
は、すべての警告をエラーに変換します。ただし、特定の警告に対してgccで選択的に実行できるとは思わない。
外部ライブラリからのヘッダーファイルがそれらの一部をトリップする可能性があるため、おそらく、プロジェクトごとに有効にする警告を選択する必要があることがわかります(特に-Werror
を使用する場合)。 (-pedantic
は、私の経験では、この点で特に役に立たない傾向があります。)
-Wmissing-prototypes
:前のプロトタイプ宣言なしでグローバル関数が定義されている場合。-Wformat-security
:考えられるセキュリティの問題を表すフォーマット関数の使用について警告します。現在、これは、書式文字列が文字列リテラルではなく、書式引数がないprintf
およびscanf
関数の呼び出しについて警告します-Werror=return-type
:gccで関数に戻りがない場合にエラーを強制します。 Visual Studioでは/we4716
です。
-Werror=implicit-function-declaration
:定義されていない/含まれていない関数を使用するとエラーが発生します。 Visual Studioでは/we4013
です。
-Werror=incompatible-pointer-types
:ポインターのタイプが予想されるポインタータイプと一致しない場合のエラー。 Visual Studioでは/we4133
です。
実際、Cコードをクロスプラットフォームに保ちたいので、CMakeを使用し、提供されているcflagsをCMakeLists.txtに次のように入れます。
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4013 /we4133 /we4716")
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=return-type")
endif()