コンパイラの警告 (レベル 3) C4996

"非推奨" とされた関数、クラス メンバー、変数、または typedef がコードで使用されています。 シンボルが非推奨であることを示すために、__declspec(deprecated) 修飾子、または C++14 の [[deprecated]] 属性が使用されます。 実際の C4996 警告メッセージは、宣言の deprecated 修飾子または属性によって指定されます。

重要

この警告は常に、シンボルを宣言するヘッダー ファイルの作成者からの意図的なメッセージです。 結果を理解していない場合は、非推奨のシンボルを使用しないでください。

解説

Visual Studio ライブラリの多くの関数、メンバー関数、関数テンプレート、グローバル変数は、"非推奨" です。 POSIX や Microsoft 固有の関数など、一部は、別の名前が優先されるようになったため非推奨です。 一部の C ランタイム ライブラリ関数は、安全でなく、より安全な変種があるため非推奨です。 その他は古いため非推奨です。 非推奨のメッセージでは通常、非推奨の関数またはグローバル変数に代えて使用できる修正候補が示されます。

/sdl (追加のセキュリティ チェックを有効にする) コンパイラ オプションを使用すると、この警告がエラーに昇格されます。

警告をオフにする

C4996 の問題を解決するには、通常は、コードを変更することをお勧めしています。 代わりに、提案された関数とグローバル変数を使用してください。 移植性の理由から既存の関数または変数を使用する必要がある場合は、警告をオフにできます。

特定のコード行に対する警告をオフにする

特定のコード行に対する警告をオフにするには、warning pragma の #pragma warning(suppress : 4996) を使用します。

ファイル内で警告をオフにする

ファイル内のそれ以降すべての要素に対する警告をオフにするには、警告 pragma #pragma warning(disable : 4996) を使用します。

コマンド ライン ビルドで警告をオフにする

コマンド ライン ビルドでグローバルに警告をオフにするには、/wd4996 コマンド ライン オプションを使用します。

Visual Studio でプロジェクトの警告をオフにする

Visual Studio IDE でプロジェクト全体の警告をオフにするには、次のようにします:

  1. プロジェクトの [プロパティ ページ] ダイアログを開きます。 [プロパティ ページ] ダイアログの使用方法の詳細については、プロパティ ページを参照してください。

  2. [構成プロパティ]>[C/C++]>[詳細] プロパティ ページを選択します。

  3. [特定の警告を無効にする] プロパティを編集して 4996 を追加します。 [OK] をクリックして変更を適用します。

プリプロセッサ マクロを使用して警告を無効にする

プリプロセッサ マクロを使用して、ライブラリで使用される特定のクラスの非推奨警告をオフにすることもできます。 これらのマクロについては、以下で説明します。

Visual Studio でプリプロセッサ マクロを定義するには、次の手順に従います。

  1. プロジェクトの [プロパティ ページ] ダイアログを開きます。 [プロパティ ページ] ダイアログの使用方法の詳細については、プロパティ ページを参照してください。

  2. [構成プロパティ] > [C/C++] > [プリプロセッサ] の順に展開します。

  3. [プリプロセッサの定義] プロパティで、マクロ名を追加します。 [OK] を選んで保存し、プロジェクトをリビルドします。

特定のソース ファイルでのみマクロを定義するには、ヘッダー ファイルをインクルードする行の前に #define EXAMPLE_MACRO_NAME などの行を追加します。

C4996 警告およびエラーの一般的な原因のいくつかを次に示します。

POSIX 関数名

The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: new-name. See online help for details.

Microsoft では、実装によって定義される予約名とグローバル名に関する C99 と C++03 の制約に準拠するために、CRT に含まれる一部の POSIX および Microsoft 固有のライブラリ関数の名前を変更しました。 "非推奨とされるのは名前だけであり、関数自体ではありません"。 ほとんどの場合、準拠した名前を作成するため関数名の先頭にアンダースコアが追加されています。 コンパイラは、元の関数名は使用されなくなったとの警告を発し、優先名を提案します。

この問題を解決するには、通常、提案された関数名を代わりに使用するようにコードを変更することをお勧めします。 ただし、更新された名前は Microsoft 固有のものです。 移植性の理由から既存の関数名を使用する必要がある場合は、これらの警告をオフにできます。 関数は、ライブラリでは元の名前で引き続き使用できます。

これらの関数が使用されなくなったとの警告をオフにするには、プリプロセッサ マクロ _CRT_NONSTDC_NO_WARNINGS を定義します。 コマンド ラインでオプション /D_CRT_NONSTDC_NO_WARNINGS を含めれば、このマクロを定義できます。

安全でない CRT ライブラリ関数

This function or variable may be unsafe. Consider using safe-version instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

より安全なバージョンが利用可能であるため、Microsoft では、一部の CRT および C++ 標準ライブラリ関数とグローバルを非推奨にしました。 非推奨の関数のほとんどで、バッファーへの未チェックの読み取りまたは書き込みアクセスが許可されます。 これらの使い方を誤ると、重大なセキュリティの問題につながる可能性があります。 コンパイラは、これらの関数は使用されなくなったとの警告を発し、優先関数を提案します。

この問題を解決するには、代わりに関数または変数の safe-version を使用することをお勧めします。 しかし、移植性または下位互換性のためという理由で、それが叶わない場合があります。 コードでバッファーの上書きまたはオーバーリードが発生する可能性がないことを慎重に確認してください。 その後、警告をオフにできます。

CRT のこれらの関数が使用されなくなったとの警告をオフにするには、_CRT_SECURE_NO_WARNINGS を定義します。

非推奨のグローバル変数に関する警告をオフにするには、_CRT_SECURE_NO_WARNINGS_GLOBALS を定義します。

これらの非推奨の関数とグローバルの詳細については、「CRT のセキュリティ機能」および「安全なライブラリ: C++ 標準ライブラリ」を参照してください。

安全でない標準ライブラリ関数

'std:: function_name ::_Unchecked_iterators::_Deprecate' Call to std:: function_name with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'

Visual Studio 2015 では、特定の C++ 標準ライブラリ関数テンプレートでパラメーターの正しさがチェックされないため、デバッグ ビルドでこの警告が表示されます。 それは多くの場合、コンテナーの境界をチェックするための十分な情報を関数が入手できないためです。 または、関数で反復子が正しく使用されていない可能性があるためです。 この警告は、これらの関数を特定するのに役立ちます。なぜなら、そのような関数は、プログラムの重大なセキュリティ ホールの原因である可能性があるからです。 詳細については、「Checked Iterators」を参照してください。

たとえば、単純配列の代わりに要素ポインターを std::copy に渡した場合、デバッグ モードでこの警告が表示されます。 この問題を解決するには、配列エクステントと境界のチェックをライブラリが実行できるよう、適切に宣言された配列を使用します。

// C4996_copyarray.cpp
// compile with: cl /c /W4 /D_DEBUG C4996_copyarray.cpp
#include <algorithm>

void example(char const * const src) {
    char dest[1234];
    char * pdest3 = dest + 3;
    std::copy(src, src + 42, pdest3); // C4996
    std::copy(src, src + 42, dest);   // OK, copy can tell that dest is 1234 elements
}

C++14 では、いくつかの標準ライブラリ アルゴリズムが更新され、"二重範囲" バージョンを備えるようになりました。 二重範囲バージョンを使用する場合、2 番目の範囲では必要な境界チェックが提供されます。

// C4996_containers.cpp
// compile with: cl /c /W4 /D_DEBUG C4996_containers.cpp
#include <algorithm>

bool example(
    char const * const left,
    const size_t leftSize,
    char const * const right,
    const size_t rightSize)
{
    bool result = false;
    result = std::equal(left, left + leftSize, right); // C4996
    // To fix, try this form instead:
    // result = std::equal(left, left + leftSize, right, right + rightSize); // OK
    return result;
}

次の例では、標準ライブラリを使用して反復子の使用状況をチェックする方法と、チェックしないまま使用すると危険な可能性がある状況について、さらにいくつか示します。

// C4996_standard.cpp
// compile with: cl /EHsc /W4 /MDd C4996_standard.cpp
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <numeric>
#include <string>
#include <vector>

using namespace std;

template <typename C> void print(const string& s, const C& c) {
    cout << s;

    for (const auto& e : c) {
        cout << e << " ";
    }

    cout << endl;
}

int main()
{
    vector<int> v(16);
    iota(v.begin(), v.end(), 0);
    print("v: ", v);

    // OK: vector::iterator is checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    vector<int> v2(16);
    transform(v.begin(), v.end(), v2.begin(), [](int n) { return n * 2; });
    print("v2: ", v2);

    // OK: back_insert_iterator is marked as checked in debug mode
    // (i.e. an overrun is impossible)
    vector<int> v3;
    transform(v.begin(), v.end(), back_inserter(v3), [](int n) { return n * 3; });
    print("v3: ", v3);

    // OK: array::iterator is checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    array<int, 16> a4;
    transform(v.begin(), v.end(), a4.begin(), [](int n) { return n * 4; });
    print("a4: ", a4);

    // OK: Raw arrays are checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    // NOTE: This applies only when raw arrays are
    // given to C++ Standard Library algorithms!
    int a5[16];
    transform(v.begin(), v.end(), a5, [](int n) { return n * 5; });
    print("a5: ", a5);

    // WARNING C4996: Pointers cannot be checked in debug mode
    // (i.e. an overrun triggers undefined behavior)
    int a6[16];
    int * p6 = a6;
    transform(v.begin(), v.end(), p6, [](int n) { return n * 6; });
    print("a6: ", a6);

    // OK: stdext::checked_array_iterator is checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    int a7[16];
    int * p7 = a7;
    transform(v.begin(), v.end(),
        stdext::make_checked_array_iterator(p7, 16),
        [](int n) { return n * 7; });
    print("a7: ", a7);

    // WARNING SILENCED: stdext::unchecked_array_iterator
    // is marked as checked in debug mode, but it performs no checking,
    // so an overrun triggers undefined behavior
    int a8[16];
    int * p8 = a8;
    transform( v.begin(), v.end(),
        stdext::make_unchecked_array_iterator(p8),
        [](int n) { return n * 8; });
    print("a8: ", a8);
}

コードでバッファー オーバーラン エラーが発生する可能性がないことを確認したら、この警告をオフにすることができます。 これらの関数の警告をオフにするには、_SCL_SECURE_NO_WARNINGS を定義します。

チェックを行う反復子が有効

_ITERATOR_DEBUG_LEVEL が 1 または 2 と定義されている状況で、チェックを行う反復子を使用しない場合にも、C4996 が発生する可能性があります。 デバッグ モード ビルドでは既定で 2 に、リテール ビルドでは 0 に設定されます。 詳細については、「Checked Iterators」を参照してください。

// C4996_checked.cpp
// compile with: /EHsc /W4 /MDd C4996_checked.cpp
#define _ITERATOR_DEBUG_LEVEL 2

#include <algorithm>
#include <iterator>

using namespace std;
using namespace stdext;

int main() {
    int a[] = { 1, 2, 3 };
    int b[] = { 10, 11, 12 };
    copy(a, a + 3, b + 1);   // C4996
    // try the following line instead:
    // copy(a, a + 3, checked_array_iterator<int *>(b, 3));   // OK
}

安全でない MFC または ATL コード

C4996 は、セキュリティ上の理由から非推奨とされた MFC 関数または ATL 関数を使用している場合に発生することがあります。

この問題を解決するには、更新された関数を代わりに使用するようにコードを変更することを強く推奨します。

これらの警告を抑制する方法については、_AFX_SECURE_NO_WARNINGS を参照してください。

古い CRT の関数と変数

This function or variable has been superseded by newer library or operating system functionality. Consider using new_item instead. See online help for details.

一部のライブラリ関数およびグローバル変数は非推奨とされるため使用されていません。 これらの関数および変数は、将来のバージョンのライブラリでは削除される可能性があります。 コンパイラは、これらの項目は使用されなくなったとの警告を発行し、優先すべき代替項目を提案します。

この問題を解決するには、提案された関数または変数を使用するようにコードを変更することをお勧めします。

これらの項目が使用されなくなったとの警告をオフにするには、_CRT_OBSOLETE_NO_WARNINGS を定義します。 詳しくは、非推奨の関数または変数のドキュメントをご覧ください。

CLR コードのマーシャリング エラー

C4996 は、CLR マーシャリング ライブラリを使用する場合にも発生することがあります。 この場合、C4996 はエラーであり、警告ではありません。 このエラーは、marshal_as を使用して、marshal_context クラスを必要とする 2 つのデータ型の間で変換を行うときに発生します。 マーシャリング ライブラリが変換をサポートしていないときにもこのエラーが発生することがあります。 マーシャリング ライブラリの詳細については、「C++ におけるマーシャリングの概要」を参照してください。

この例では、マーシャリング ライブラリが System::Stringconst char * に変換するときにコンテキストを必要とするため、C4996 が生成されます。

// C4996_Marshal.cpp
// compile with: /clr
// C4996 expected
#include <stdlib.h>
#include <string.h>
#include <msclr\marshal.h>

using namespace System;
using namespace msclr::interop;

int main() {
   String^ message = gcnew String("Test String to Marshal");
   const char* result;
   result = marshal_as<const char*>( message );
   return 0;
}

例: ユーザー定義の非推奨関数

独自のコードで deprecated 属性を使用すると、特定の関数の使用を推奨しなくなった場合にそのことを呼び出し元に警告できます。 この例では、C4996 は、非推奨の関数が宣言されている行と、関数が使用されている行の 2 か所で発生します。

// C4996.cpp
// compile with: /W3
// C4996 warning expected
#include <stdio.h>

// #pragma warning(disable : 4996)
void func1(void) {
   printf_s("\nIn func1");
}

[[deprecated]]
void func1(int) {
   printf_s("\nIn func2");
}

int main() {
   func1();
   func1(1);    // C4996
}