プログラミング、リファクタリング、そしてすべてにおける究極の疑問: No. 30

同カテゴリーの次の記事

プログラミング、リファクタリング、そしてすべてにおける究極の疑問: No. 31

この記事は、インテル® デベロッパー・ゾーンに公開されている「The Ultimate Question of Programming, Refactoring, and Everything」の日本語参考訳です。


30. Visual C++* と wprintf() 関数

Energy Checker SDK プロジェクトから抜粋した以下のコードについて考えてみます。このコードにはエラーが含まれています。PVS-Studio アナライザーは、次の診断を出力します。

V576 Incorrect format. Consider checking the second actual argument of the ‘wprintf’ function. The pointer to string of wchar_t type symbols is expected. (V576 不正な形式です。’wprintf’ 関数の第 2 実引数を確認してください。wchar_t 型のシンボルの文字列へのポインターが想定されます。)

int main(void) {
  ...
  char *p = NULL;
  ...
  wprintf(
    _T("Using power link directory: %s\n"), 
    p
  );
  ...
}

説明

注: 最初のエラーは、ワイド文字形式の文字列の指定に _T を使用しているためです。ここでは、L プリフィクスを使用します。しかし、これは重大なミスではなく、注目に値しません。ワイド文字形式を使用しないと _T は展開されず、コードがコンパイルされないだけです。

wprintf() 関数で char* 型の文字列を出力するには、書式設定文字列で “%S” を使用すべきです。

多くの Linux* プログラマーは、この落とし穴に気付かないでしょう。Microsoft* は、wsprintf などの関数を奇妙な方法で実装しています。Visual C++* で wsprintf 関数を使用する場合、ワイド文字の文字列の出力には “%s” を使用し、char* 文字列の出力には “%S” を使用すべきです。単に奇妙なケースと言えるでしょう。これは、クロスプラットフォーム・アプリケーションを開発する場合に陥りやすい罠です。

正しいコード

ここで紹介するコードは、美しいものではありませんが、修正すべき点を示しています。

char *p = NULL;
...
#ifdef defined(_WIN32)
wprintf(L"Using power link directory: %S\n"), p);
#else
wprintf(L"Using power link directory: %s\n"), p);
#endif

推奨事項

ここでは、特に推奨事項はありません。wprintf() のような関数を使用する場合に起こりうる意外な問題について、皆さんに警告したかっただけです。

Visual Studio* 2015 以降では、可搬性の高いコードを記述するための推奨があります。ISO C (C99) との互換性のため、プリプロセッサーに _CRT_STDIO_ISO_WIDE_SPECIFIERS マクロについて知らせるべきです。

この場合、次のコードは正しいです。

const wchar_t *p = L"abcdef";
const char *x = "xyz";
wprintf(L"%S %s", p, x);

アナライザーは、_CRT_STDIO_ISO_WIDE_SPECIFIERS を認識し、解析時に考慮します。

ISO C との互換性を有効にする (_CRT_STDIO_ISO_WIDE_SPECIFIERS マクロが宣言されている) 場合、”%Ts” 形式の指示子を使用して以前の動作にすることができます。

一般に、ワイド文字シンボルはかなり複雑で、短い記事ではカバーできません。このトピックに関してさらに詳しく調査するには、次の資料が参考になります。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事

  • Parallel Universe マガジンParallel Universe マガジン Parallel Universe へようこそ。 米国インテル社が四半期に一度オンラインで公開しているオンラインマガジンです。インテルの技術者によるテクノロジーの解説や、最新ツールの紹介など、並列化に関する記事を毎号掲載しています。第1号からのバックナンバーを PDF 形式で用意しました、ぜひご覧ください。 12 […]
  • 比較関数の罠比較関数の罠 この記事は、インテル® デベロッパー・ゾーンに公開されている「The Evil within the Comparison Functions」の日本語参考訳です。 この記事の PDF […]
  • インテル® Inspector XE 2013 を使用してアプリケーションのメモリー使用量の増加を検出する方法インテル® Inspector XE 2013 を使用してアプリケーションのメモリー使用量の増加を検出する方法 この記事は、インテル® ソフトウェア・サイトに掲載されている「How to detect application memory growth using Intel® Inspector XE 2013」の日本語参考訳です。 背景 インテル® Inspector XE 2013 […]
  • インテル® IPP サンプル – エラーの修正インテル® IPP サンプル – エラーの修正 この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Intel IPP Samples for Windows - error correction」の日本語参考訳です。 この記事は、PVS-Studio を使用することでプログラムがどのように安全になるかを説明した記事の 1 […]
  • 並列プログラミングにおけるロックの効率的な使用並列プログラミングにおけるロックの効率的な使用 この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Using Locks Effectively in Parallel Programming […]