gccのコマンドラインオプションを眺めてて新たに知ったこととかを紹介する（C言語・C++編）

[gccのコマンドラインオプションを眺めてて新たに知ったこととかを紹介する（言語非依存編）](http://qiita.com/h_hiro_/items/4db6a7478fb0ff333d9f "gccのコマンドラインオプションを眺めてて新たに知ったこととかを紹介する（言語非依存編） - Qiita")の続きです。

# はじめに

-   日本語訳もあるにはありますが、（現時点での）最新版を参照したかったので、英語を提示した上で私訳を一緒に載せます。
    原文はこちら：[Using the GNU Compiler Collection (GCC)](https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/)（gcc 6.3.0用ドキュメント）
-   C言語・C++に関連するオプションのみ掲載します。言語非依存のオプションについては、前回の記事（[言語非依存編](http://qiita.com/h_hiro_/items/4db6a7478fb0ff333d9f "gccのコマンドラインオプションを眺めてて新たに知ったこととかを紹介する（言語非依存編） - Qiita")）をご覧ください。

# それでは紹介します

## C言語向け（C++に共通なものも含む）

[3.4 Options Controlling C Dialect](https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/C-Dialect-Options.html "C Dialect Options - Using the GNU Compiler Collection (GCC)")

### -fno-asm

>   Do not recognize asm, inline or typeof as a keyword, so that code can use these words as identifiers. You can use the keywords \_\_asm\_\_, \_\_inline\_\_ and \_\_typeof\_\_ instead. -ansi implies -fno-asm.
>   In C++, this switch only affects the typeof keyword, since asm and inline are standard keywords. You may want to use the -fno-gnu-keywords flag instead, which has the same effect. In C99 mode (-std=c99 or -std=gnu99), this switch only affects the asm and typeof keywords, since inline is a standard keyword in ISO C99. 

`asm`・`inline`・`typeof`をキーワード（予約語）として扱わず、単なる識別子と扱う。これらのキーワードが必要な場合は`__asm__`・`__inline__`・`__typeof__`を使う。`-ansi`オプションを指定した場合、`-fno-asm`も指定されている状態になる。
C++の場合、`asm`・`inline`はそもそも標準のキーワード（すなわち予約語）であるため、このオプションは`typeof`にのみ効く。また規格としてC99を指定している場合（`-std=c99`ないし`-std=gnu99`）、`inline`が標準のキーワードであるので、このオプションは`asm`・`typeof`にのみ効く。
※**補足**：すなわち、本来予約語ではないこれらの単語を、（gccはデフォルトでは予約語扱いするものの）予約語と扱わないと指定することを意味する。

### -fno-builtin

>   Don't recognize built-in functions that do not begin with '\_\_builtin\_' as prefix. See [Other built-in functions provided by GCC](https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Other-Builtins.html "Other Builtins - Using the GNU Compiler Collection (GCC)"), for details of the functions affected, including those which are not built-in functions when -ansi or -std options for strict ISO C conformance are used because they do not have an ISO standard meaning.
>   GCC normally generates special code to handle certain built-in functions more efficiently; for instance, calls to alloca may become single instructions which adjust the stack directly, and calls to memcpy may become inline copy loops. The resulting code is often both smaller and faster, but since the function calls no longer appear as such, you cannot set a breakpoint on those calls, nor can you change the behavior of the functions by linking with a different library. In addition, when a function is recognized as a built-in function, GCC may use information about that function to warn about problems with calls to that function, or to generate more efficient code, even if the resulting code still contains calls to that function. For example, warnings are given with -Wformat for bad calls to printf when printf is built in and strlen is known not to modify global memory.

'\_\_builtin\_'で始まるのではないビルトイン関数を認識しない。これによる影響を受ける関数（`-ansi`ないし`-std`オプションがある場合にビルトイン関数ではなくISO Cの標準に合わせたものが使われるもの、という情報も含む）については、[Other built-in functions provided by GCC](https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Other-Builtins.html "Other Builtins - Using the GNU Compiler Collection (GCC)")を参照。
gccは通常、一部のビルトイン関数に対して効率的に動作するようなコードを生成する。例えば、`alloca`がスタックを直接操作する単一の処理となっていたり、`memcpy`がインライン展開されたループになっていたりする場合がある。これは通常、コードを小さくすることや高速化に役立つものであるのだが、一方でそこに関数呼び出しという挙動が入らないため、ブレークポイントが設定できなかったり、関数のリンク先を変えることで挙動を変えたりということができなくなる。またビルトイン関数を利用している場合において、gccはその関数を呼び出すことに対する警告を出したり、より効率的なコードを生成したりできる。例えば、`-Wformat`オプションを指定することで`printf`の引数に問題があると警告を出すこと[^1]や、`strlen`がグローバルなメモリを改変しないと保証することは、それらがビルトインであればできる。

### -fhosted / -ffreestanding

>   Assert that compilation targets a hosted environment. This implies -fbuiltin. A hosted environment is one in which the entire standard library is available, and in which main has a return type of int. Examples are nearly everything except a kernel. This is equivalent to -fno-freestanding.

コンパイル対象がホストされた環境である。この場合、`-fbuiltin`が指定されているとみなされる。ホストされた環境とは、標準ライブラリがすべて利用でき、`int`を返す関数`main`が定義されている環境である。カーネル以外であればだいたいこの環境となる。`-fno-freestanding`も同義である。

※特記しない限り、これはデフォルトで指定されている。
※逆に`-ffreestanding`ないし`-fno-hosted`を指定すると、標準ライブラリがなく、`main`関数があるとは限らない、カーネルを作るときなど向けの環境となる。

### -fcond-mismatch

>   Allow conditional expressions with mismatched types in the second and third arguments. The value of such an expression is void. This option is not supported for C++. 

条件演算子において、第2引数（第1引数が真である場合の結果）と第3引数（第1引数が偽である場合の結果）の型が異なっていることを許す。この場合、この式全体の型は`void`となる。C++では利用できない。

※**注**：gcc6.3.0で試してみたところ、このオプションがなくても利用できた（C++ではエラー）。

```c
#include <stdio.h>

int foo(void){
    printf("FOO\n");
    return 1;
}

void bar(void){
    printf("BAR\n");
}

int main(void){
    int x = 5;
    
    //C言語では通るが、C++はエラー
    (x > 5) ? foo() : bar();
    return 0;
}
```

## C++向け

[3.5 Options Controlling C++ Dialect](https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/C_002b_002b-Dialect-Options.html#C_002b_002b-Dialect-Options "C++ Dialect Options - Using the GNU Compiler Collection (GCC)")

### -fno-access-control

>   Turn off all access checking. This switch is mainly useful for working around bugs in the access control code. 

アクセス権（`private`、`protected`など）のチェックを無効にする。主に、アクセス権に関わるコードのバグの確認に役立つ。

### -fno-elide-constructors

>   The C++ standard allows an implementation to omit creating a temporary that is only used to initialize another object of the same type. Specifying this option disables that optimization, and forces G++ to call the copy constructor in all cases.

C++の標準では、同じ型の他のオブジェクトを初期化するためだけに使われる一時的なオブジェクトを作る、という操作を省略するという実装にすることが認められている。このオプションを指定すると、この最適化された処理を行わず、必ずコピーコンストラクタが呼ばれる。

※サンプルコード https://wandbox.org/permlink/sx6DgeyPKnEaaj6A
このページ左側の「Compiler options」の箇所に「-fno-elide-constructors」が指定されているため、「Run」ボタンでこれをコンパイルし実行すると「Constructed」だけでなく「Copy-constructed」も表示される。「-fno-elide-constructors」の部分を消してからコンパイルし実行すると、「Copy-constructed」は表示されなくなる。

### -fno-enforce-eh-specs

>   Don't generate code to check for violation of exception specifications at run time. This option violates the C++ standard, but may be useful for reducing code size in production builds, much like defining NDEBUG. This does not give user code permission to throw exceptions in violation of the exception specifications; the compiler still optimizes based on the specifications, so throwing an unexpected exception results in undefined behavior at run time. 

例外の指定に反していることを実行時にチェックするコードを生成しない。これはC++の標準に反する挙動ではあるものの、実際に利用するコードを小さくするために役立つ。これは例外の指定に違反するコードを書いてよいというわけではなく、指定に違反がないという想定でコードが最適化されるというだけであり、指定に反した例外を投げた場合の動作は未定義である。

### -fno-implicit-templates

>   Never emit code for non-inline templates that are instantiated implicitly (i.e. by use); only emit code for explicit instantiations. See [Template Instantiation](https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Template-Instantiation.html "Template Instantiation - Using the GNU Compiler Collection (GCC)"), for more information.

インラインではないテンプレートに対し、明示的なインスタンス化がなされない限りそのコードを生成しない（利用しようとしただけではインスタンス化されない）。

### -fno-pretty-templates
>   When an error message refers to a specialization of a function template, the compiler normally prints the signature of the template followed by the template arguments and any typedefs or typenames in the signature (e.g. void f(T) [with T = int] rather than void f(int)) so that it's clear which template is involved. When an error message refers to a specialization of a class template, the compiler omits any template arguments that match the default template arguments for that template. If either of these behaviors make it harder to understand the error message rather than easier, you can use -fno-pretty-templates to disable them.

エラーメッセージが、関数テンプレートの特殊化によって得られる関数を参照する場合、通常は「テンプレートを書き、その後にテンプレート引数とその型名あるいは`typedef`を記載する」となる（例えば、`void f(T) [with T = int]`という具合。`void f(int)`ではなく）。これはどのテンプレートが原因なのか明確するためのものである。またエラーメッセージが、クラステンプレートの特殊化によって得られるクラスを参照する場合、テンプレートのデフォルト引数が指定されていればそれを省略する。これらの挙動があるとエラーメッセージがわかりにくい場合、このオプションを指定するとこれらの挙動を無効にできる。

### -fsized-deallocation

[サイズ付きデアロケーション](https://cpprefjp.github.io/lang/cpp14/sized_deallocation.html "サイズ付きデアロケーション - cpprefjp C++日本語リファレンス")を有効にする。C++14では標準化されている。

### -Wnon-virtual-dtor

警告オプションであるものの、"-Wall"オプションでは有効にならない。

>   Warn when a class has virtual functions and an accessible non-virtual destructor itself or in an accessible polymorphic base class, in which case it is possible but unsafe to delete an instance of a derived class through a pointer to the class itself or base class. This warning is automatically enabled if -Weffc++ is specified.

もしクラスが、仮想関数を持っていて、かつアクセス可能な（publicなどであるために参照可能、ということ?）非仮想デストラクタをそれ自身か多態な基底クラスに持っている場合、警告する。これはデストラクタを実行することは可能であるものの、ポインタを通して継承されたクラスのインスタンスをdeleteできるという安全でない状態が発生する。`-Weffc++`（後述）を指定すればこれも有効化される。

### -Weffc++

警告オプションであるものの、"-Wall"オプションでは有効にならない。

>   Warn about violations of the following style guidelines from Scott Meyers' Effective C++ series of books:
>   - Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
>   - Prefer initialization to assignment in constructors.
>   - Have operator= return a reference to *this.
>   - Don't try to return a reference when you must return an object.
>   - Distinguish between prefix and postfix forms of increment and decrement operators.
>   - Never overload &&, ||, or ,. 
>
>   This option also enables -Wnon-virtual-dtor, which is also one of the effective C++ recommendations. However, the check is extended to warn about the lack of virtual destructor in accessible non-polymorphic bases classes too.
>   When selecting this option, be aware that the standard library headers do not obey all of these guidelines; use ‘grep -v’ to filter out those warnings.

Scott Meyersの書籍「Effective C++」シリーズで記述されている、以下のスタイルガイドラインについて、沿っていないものを警告する。

- 動的に確保されるメモリを持つクラスに対しては、コピーコンストラクタと代入演算子を定義する。
- コンストラクタにおいては、代入よりも初期化を利用する。
- `operator=`は`*this`への参照を返す。
- オブジェクトを返り値にする際は、参照を返さない。
- インクリメント・デクリメント演算子の前置と後置を区別する。
- `&&`、'||'、','をオーバーロードしない。

また、このオプションは`-Wnon-virtual-dtor`（前述）が指定されているとみなす。これもまたeffective C++で薦められていることである。ただしこれにより、アクセス可能な非仮想デストラクタが非多態な基底クラスにない場合にも警告が出る。
標準ライブラリのヘッダがこのガイドラインに従っていない場合があるため、このオプションを指定した場合は、`grep -v`で標準ライブラリからの警告を除外するとよい。

### -Wold-style-cast

警告オプションであるものの、"-Wall"オプションでは有効にならない。

>   Warn if an old-style (C-style) cast to a non-void type is used within a C++ program. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and much easier to search for.

古い（C言語の方式の）キャストが、`void`以外の型へのキャストに利用されていた場合、警告する。新しいキャスト（`dynamic_cast`、`static_cast`、`reinterpret_cast`、`const_cast`）のほうが、意図しない結果を出しにくく、また検索も容易である。

----

[^1]: C言語の可変長引数の仕様では、引数の数や渡す変数の型に制限がなく、かつそれを実行時にもコンパイル時にも確かめる方法がない。