MFCプロジェクトをx64でビルドすると、32bitでは出なかったC4267やC4244が現れることがあります。この記事では、size_t、ptrdiff_t、INT_PTRをintへ縮小している箇所を見分け、安全な型へ直す方法を扱います。
C4267とC4244で最初に見る型
| 警告 | よくある式 | 最初に検討する修正 |
|---|---|---|
C4267 | size_tからint | 要素数や添字をsize_tのまま扱う |
C4244 | ptrdiff_tからint | ポインタ差をptrdiff_tのまま扱う |
| MFCコレクション | GetSize()からint | INT_PTRで受ける |
| 32bit幅のAPI引数 | size_tからDWORD | MAXDWORD以下を確認してから変換する |
x64ではintとDWORDは4バイトのままですが、size_t、ptrdiff_t、INT_PTRは8バイトになります。警告は、8バイト側で表せる値を4バイト側へ入れたときに情報を失う可能性を知らせています。

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がintやDWORDを要求する場合は、明示キャストの前に値が宛先の範囲へ収まるかを確認します。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段階で直す
- 警告行の右辺と左辺の型を確認します。
- 件数、添字、ポインタ差なら、計算元と同じ幅の型へ変更します。
- 狭い型がAPI仕様として必要な場合だけ、上限を確認して明示変換します。
#pragma warning(disable: 4267)やプロジェクト全体の警告レベル変更は、別の縮小変換まで見えなくします。まず型を合わせ、変換が仕様上必要な行だけ範囲確認を置くのが基本です。
まとめ
- C4267では
size_tをintへ縮小せず、件数と添字をsize_tで扱います。 - C4244でポインタ差を縮小している場合は、
ptrdiff_tで保持します。 - MFCコレクションの
GetSize()はINT_PTRで受けます。 intやDWORDへの変換が必要なら、宛先の上限を確認してからキャストします。
