【MFC】C4267・C4244を64bit移行で解消する型の直し方

【MFC】C4267・C4244を64bit移行で解消する型の直し方

MFCプロジェクトをx64でビルドすると、32bitでは出なかったC4267やC4244が現れることがあります。この記事では、size_tptrdiff_tINT_PTRintへ縮小している箇所を見分け、安全な型へ直す方法を扱います。

目次

C4267とC4244で最初に見る型

警告よくある式最初に検討する修正
C4267size_tからint要素数や添字をsize_tのまま扱う
C4244ptrdiff_tからintポインタ差をptrdiff_tのまま扱う
MFCコレクションGetSize()からintINT_PTRで受ける
32bit幅のAPI引数size_tからDWORDMAXDWORD以下を確認してから変換する

x64ではintDWORDは4バイトのままですが、size_tptrdiff_tINT_PTRは8バイトになります。警告は、8バイト側で表せる値を4バイト側へ入れたときに情報を失う可能性を知らせています。

Visual Studio 2026のDebug x64で確認したC4267・C4244の型サイズと修正方針

C4267はsize_tをintへ縮小しない

std::vector::size()の戻り値はsize_tです。件数をintへ代入せず、受け側とループカウンタをsize_tへ合わせます。

std::vector<int> values = { 10, 20, 30, 40 };

// C4267: size_t から int への縮小
int count = values.size();

// 修正: 件数と添字を size_t のまま扱う
const size_t safeCount = values.size();
for (size_t i = 0; i < safeCount; ++i)
{
    TRACE(_T("values[%zu] = %d\n"), i, values[i]);
}

Microsoft LearnのC4267の説明も、size_tまたは同等以上の幅の整数型へ合わせる方法を示しています。MFCのCArray::GetSize()CStringArray::GetSize()INT_PTRを返すため、MFCコレクションの添字もINT_PTRへ合わせます。

CStringArray names;
names.Add(_T("Alpha"));
names.Add(_T("Beta"));

for (INT_PTR i = 0; i < names.GetSize(); ++i)
{
    TRACE(_T("names[%lld] = %s\n"),
          static_cast<long long>(i),
          static_cast<LPCTSTR>(names.GetAt(i)));
}

C4244はポインタ差をptrdiff_tで受ける

2つのポインタやランダムアクセスイテレータの差は、x64ではintより広い型になります。距離をintへ代入するとC4244が出る場合は、計算結果をptrdiff_tで保持します。

const int* first = values.data();
const int* last = first + values.size();

// C4244: x64ではポインタ差をintへ縮小する
int distance = last - first;

// 修正: ポインタ差の型を保つ
const std::ptrdiff_t safeDistance = last - first;

警告番号だけで一律にキャストせず、式の元の型を確認してください。Microsoft LearnのC4244の説明にはx64のポインタ差の例がありますが、C4244は浮動小数点数から整数への変換などでも出るため、すべてが64bit移行に由来するとは限りません。

intやDWORDが必要なら範囲を確認する

変更できないAPIがintDWORDを要求する場合は、明示キャストの前に値が宛先の範囲へ収まるかを確認します。static_castを書くだけでは、切り詰めの危険は消えません。

bool TrySizeToInt(size_t value, int& result)
{
    if (value > static_cast<size_t>((std::numeric_limits<int>::max)()))
        return false;

    result = static_cast<int>(value);
    return true;
}

bool TrySizeToDword(size_t value, DWORD& result)
{
    if (value > static_cast<size_t>(MAXDWORD))
        return false;

    result = static_cast<DWORD>(value);
    return true;
}

変換失敗をASSERTだけで処理すると、Releaseビルドでは検査がなくなります。実データで上限を超える可能性がある箇所では、戻り値やエラー表示で呼び出し元へ失敗を返します。

警告を抑制せず3段階で直す

  1. 警告行の右辺と左辺の型を確認します。
  2. 件数、添字、ポインタ差なら、計算元と同じ幅の型へ変更します。
  3. 狭い型がAPI仕様として必要な場合だけ、上限を確認して明示変換します。

#pragma warning(disable: 4267)やプロジェクト全体の警告レベル変更は、別の縮小変換まで見えなくします。まず型を合わせ、変換が仕様上必要な行だけ範囲確認を置くのが基本です。

まとめ

  • C4267ではsize_tintへ縮小せず、件数と添字をsize_tで扱います。
  • C4244でポインタ差を縮小している場合は、ptrdiff_tで保持します。
  • MFCコレクションのGetSize()INT_PTRで受けます。
  • intDWORDへの変換が必要なら、宛先の上限を確認してからキャストします。
目次