1. ホーム
  2. c

[解決済み】このC関数は常にfalseを返すべきですが、そうではありません。

2022-03-26 21:24:49

質問

昔、あるフォーラムで興味深い質問を偶然見つけたので、その答えを知りたいのです。

次のC関数を考えてみましょう。

f1.c

#include <stdbool.h>

bool f1()
{
    int var1 = 1000;
    int var2 = 2000;
    int var3 = var1 + var2;
    return (var3 == 0) ? true : false;
}

これは常に false というのは var3 == 3000 . その main 関数は次のようになります。

main.c

#include <stdio.h>
#include <stdbool.h>

int main()
{
    printf( f1() == true ? "true\n" : "false\n");
    if( f1() )
    {
        printf("executed\n");
    }
    return 0;
}

以降 f1() は常に false であるならば、このプログラムは1つの 虚偽 を画面に表示します。しかし、コンパイルして実行した結果 実行 も表示されます。

$ gcc main.c f1.c -o test
$ ./test
false
executed

なぜでしょうか?このコードには何か未定義の動作があるのでしょうか?

注:コンパイル時に gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2 .

解決方法は?

他の回答にもあるように、問題はあなたが gcc で、コンパイラオプションが設定されていない場合。この場合、デフォルトは "gnu90" と呼ばれるもので、1990年に撤回された古いC90標準の非標準の実装となります。

古いC90規格では、C言語には大きな欠陥がありました。関数を使う前にプロトタイプを宣言しないと、関数のデフォルトが int func () (ここで ( ) は任意のパラメータを受け入れるという意味です。) これにより、関数の呼び出し規則が変更されます。 func しかし、実際の関数定義は変更されません。のサイズが小さくなっているので boolint が異なる場合、あなたのコードは、関数が呼ばれたときに未定義の動作を呼び出します。

この危険な無意味な動作は、1999年にC99規格が発表されたことで修正された。暗黙の関数宣言は禁止されたのだ。

残念ながら、バージョン5.x.xまでのGCCは、デフォルトで古いC標準をまだ使っています。あなたのコードを標準C以外としてコンパイルしたい理由はおそらくないでしょう。ですから、あなたのコードを25年以上前の非標準のGNUのがらくたの代わりに、現代のCコードとしてコンパイルするよう、GCCに明示的に指示する必要があるのです。

常にasでコンパイルすることで、問題を解決します。

gcc -std=c11 -pedantic-errors -Wall -Wextra

  • -std=c11 は、(現在の) C 標準規格 (非公式には C11 として知られている) に従ってコンパイルするよう、半ば強制するように指示します。
  • -pedantic-errors は、上記のことを全面的に実行し、C標準に違反する不正なコードを書くとコンパイラーエラーを出すように指示します。
  • -Wall は、あった方がいいような追加の警告を出すという意味です。
  • -Wextra は、あると便利な他の警告をいくつか教えてください、という意味です。