2013年12月16日月曜日

ポインター引数に FALSE を渡してしまった…その時 C++14 では…

こちらは C++ (fork) Advent Calendar 2013 16日目の記事になります。

Advent Calendar 向けに書いていた記事ではないのですが、空いていたので…
なので内容はちょっと薄いかもしれまんが、ご容赦ください。



本の虫: C++03とC++14の違い:標準型変換編
C++14では、リテラルのみが整数nullポインター定数として扱われる。

C++03/11では、コンパイル時に値が0になる整数型もリテラルとして扱われていた。

C++14では、無用の混乱を避けるために、リテラルのみをnullポインター定数とするように改められた。

私はしばしば以下の様なコード見ることがあります。
void SetHogeHoge(int, int, void*, BOOL, BOOL) {
}

int main()
{
    SetHogeHoge(0, 0
        , FALSE // void* に FALSE を渡している!!
        , FALSE
        , FALSE
    );
    return 0;
}

おそらく SetHogeHoge の第3引数は NULL の間違いだと思われます。
SetHogeHoge の使用者はおそらく使用方法を勘違いしているか単なる typo かのどうちらかでしょう。

ここで問題なのは、上記コードは間違いだけど正常に動いてしまうことです。
動けばいいじゃんと思う方もいるかもしれませんが、
関数の意図を理解せずに書いたのだとすると、それはちょっとマズイかもしれません。

こんな間違いをする人なんていないだろーと思っていても、見かけることがあるんですよね。。。
(特に WIN32 API の呼び出しなんかで…)




さて、ここで冒頭の内容に目を向けてみましょう。
リンク先にも書いてあるように、C++14 からは整数nullポインター定数の扱いが変更になるそうです。
詳しいことは→ 本の虫: C++03とC++14の違い:標準型変換編

#include <stdio.h>

void f( void * ) { printf(__PRETTY_FUNCTION__ ); }
void f( ... ) { printf(__PRETTY_FUNCTION__ ); }

int main()
{
    f(1-1);
    return 0;
}
上記コードは C++03 と C++14 で結果が変わります。
C++03 の場合:[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
C++14 の場合:[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

で、ここからが本題。

FALSE は大抵こうです。
#define FALSE 0
これでは、C++14 になったとしてもnullポインター定数として解釈されてしまいます。
そこで、FALSE を以下のように定義します。
#define FALSE (1-1)
こうすることで、本来 nullptr を渡すべきところで誤って FALSE と書いてしまってもコンパイルエラーになるようになります。

#define FALSE (1-1)

void SetHogeHoge(int, int, void*, BOOL, BOOL) {
}

int main()
{
    SetHogeHoge(0, 0, FALSE, FALSE, FALSE);
    return 0;
}

C++03 の場合:[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
C++14 の場合:[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
(clang だと C++03 でコンパイルしても警告が出るみたい)

いや~それにしても Wandbox 便利ですね!!

0 件のコメント:

コメントを投稿