オプション沼(21) gcc、-Wuninitialized、最適化のときだけ働く、その2

Joseph Halfmoon

前回は最適化オプションの有無で挙動が異なるWarray-boundsオプションでした。同様に最適化オプションの有無が挙動に影響する警告オプションは他にもありました。今回のWuinitializedオプションもその一つです。未初期化の変数を使用しちゃったときに警告してくれるもの。Wallしていても最適化してなければザル。

※『オプション沼』投稿順indexはこちら

※今回は動作確認に以下を使用しています

    • Windows11 WSL2上のUbuntu 20.04 LTS、gccのバージョンは9.4.0
-Wuninitialized オプション

今回も最適化オプションとの組みわせて挙動が変わる警告オプションです。Wuninitializedオプションです。Wallオプションの中に含まれている警告オプションであるのですが、最適化しないと何も指摘してくれません。大人の事情ね。なお、同様な未初期化のチェックをしてくれるオプションには、

Wmaybe-uninitialized

というオプションもありました。微妙に警告範囲が異なるようにも読めるのですが、今回はその差がでるような事例を実験してません。詳細については以下の御本家ドキュメントをご覧くだせーまし。

3.8 Options to Request or Suppress Warnings

今回実験のC言語ソース

今回のソースでは上記のドキュメントに掲載例をほぼほぼそのままで「よゐこ」はやってはいけない悪い例にしてます。ある経路では値が定まるのだけれども、ある経路では値が定まらない奴です。こんな感じ。

/* option -Wuninitialized */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int f1(int sel) {
    int x;
    switch (sel)
    {
        case 1: x = 1;
            break;
        case 2: x = sel+1;
            break;
        case 3: x = sel*2;
            break;
    }
    return x;
}

int main(int argc, char const *argv[])
{
    int result = f1(1);
    printf("f1(1): %d\n", result);
    result = f1(2);
    printf("f1(2): %d\n", result);
    result = f1(3);
    printf("f1(3): %d\n", result);
    result = f1(4);
    printf("f1(4): %d\n", result);
    return 0;
}
最適化の有無による挙動の違い

さてお楽しみの最適化の有無による挙動の違いです。まずは-O0で最適化無指定です。するとこんな感じ。O0commandline

Wallだろうが、Wuninitializedだろうが、Wmaybe-uninitializedだろうが、まったく警告してくれません。ダメじゃん。

つづいて最適化してみます。-O0を-O2へ変えただけ。こんな感じ。O2commandline

警告が表示されております。ただ、Wallだろうが、Wuninitializedだろうが、結局、Wmaybe-uninitializedオプションによる警告として報告されとります。Wuninitializedの立場がないじゃん。

実行結果を一応確認

例によって、警告は警告でしかないので、実行オブジェクトは正常に生成されております。まず -O0 のときのオブジェクトを実行してみたところが以下に。uninitO0

最後のf1(4)は未初期化変数を参照しているハズだけれど、前のf1(3)のときの結果を踏襲しているような感じっす。

つづいて-O2のときの結果です。uninitO2

警告は出てますが、実行はできます。案の定、f1(4)の結果は -O0 のときとは異なってます。未初期化変数の取り扱いの違いが見えておると。

しかし、最適化しないと効かない「ツンデレ」系オプション、意外と多いのね。

オプション沼(20) gcc、-Warray-bounds、最適化のときは世話焼きになる に戻る

オプション沼(22) gcc、Wnull-dereference、最適化しないと効かない3 へ進む