C++でプログラミングをしている際に、「error: ISO C++ forbids comparison between pointer and integer [-fpermissive]」というエラーに遭遇することがあります。

このエラーは、C++の型システムにおいて互換性のない「ポインタ型」と「整数型」を比較しようとした際に発生する典型的なコンパイルエラーです。

C++は型に対して非常に厳格な言語であり、メモリアドレスを指すポインタと数値を表す整数を混同することは、重大なバグの原因となるため禁止されています。

特にC言語のスタイルに慣れている方や、文字列操作、配列処理を実装している初心者が陥りやすいミスと言えるでしょう。

本記事では、このエラーが発生する具体的な原因を整理し、最新のC++標準に基づいた正しい修正方法を詳しく解説します。

エラーメッセージが意味すること

エラー文に含まれる「ISO C++ forbids comparison between pointer and integer」は、直訳すると「ISO C++はポインタと整数の比較を禁止している」という意味です。

ここで言うポインタとは、メモリ上の特定の場所を指し示す「アドレス情報」のことです。

一方で整数は、int型やchar型などの「数値データ」そのものを指します。

C++の仕様では、これら二つを比較演算子(==, !=, <, >など)で直接比べることは許可されていません。

エラーメッセージの末尾にある[-fpermissive]は、コンパイラの設定によってはこれを警告として扱うことも可能であることを示唆していますが、現代のプログラミングにおいてはこのエラーを無視すべきではありません。

メモリアドレスと数値を比較するコードは、ほとんどの場合において「プログラマの記述ミス」であり、実行時にセグメンテーションフォールトなどの深刻な問題を引き起こすからです。

エラーが発生する主な原因

このエラーが発生するケースはいくつか決まったパターンがあります。

主な原因を以下の表にまとめました。

原因の種類具体的な内容
デリファレンスの忘れポインタが指す先の値ではなく、ポインタ自身(アドレス)を数値と比較している。
文字列と文字の混同ダブルクォーテーション(文字列リテラル)とシングルクォーテーション(文字リテラル)を誤用している。
関数の戻り値の勘違いポインタを返す関数を呼び出し、その結果を数値と比較している。
配列名の誤った使用配列名が先頭要素のアドレスとして扱われる性質を理解せず、値と比較している。

1. ポインタのデリファレンス忘れ

最も多い原因は、ポインタが指している「値」を取り出すためのデリファレンス演算子(*)の付け忘れです。

例えば、int* pというポインタ変数があるとき、pはアドレスを、*pはそこにある数値を表します。

もしif (p == 10)と書いてしまうと、アドレスと数値を比較することになり、このエラーが発生します。

2. 文字列リテラルと文字リテラルの使い分けミス

C++において、'A'(シングルクォーテーション)は文字リテラルであり、内部的にはその文字コードに対応する整数型として扱われます。

一方で、"A"(ダブルクォーテーション)は文字列リテラルであり、メモリ上のどこかに配置された文字列の先頭を指すポインタ型(char const*)として扱われます。

したがって、if (str == 'A')と書くべきところで、誤ってポインタ同士やポインタと文字コードを混同して比較するとエラーになります。

具体的なコード例と修正方法

それでは、実際によく見られるエラーコードとその修正案を見ていきましょう。

ケースA:ポインタ変数の比較ミス

以下のコードは、ポインタが指す値が0(ヌル文字など)であるかをチェックしようとして失敗している例です。

C++
#include <iostream>

int main() {
    int value = 10;
    int* ptr = &value;

    // エラー:ポインタ変数ptrと整数0を比較している
    if (ptr == 10) { 
        std::cout << "値は10です" << std::endl;
    }

    return 0;
}

このコードをコンパイルすると、まさに今回解説しているエラーが出力されます。

正しい修正方法は、ポインタの前にアスタリスクを付けて「指し示している値」にアクセスすることです。

C++
#include <iostream>

int main() {
    int value = 10;
    int* ptr = &value;

    // 修正後:デリファレンスを行い、中身の数値と比較する
    if (*ptr == 10) { 
        std::cout << "値は10です" << std::endl;
    }

    return 0;
}
実行結果
値は10です

ケースB:C言語スタイルの文字列比較

C言語スタイルの文字列(char配列やcharポインタ)を扱っている際にも、このエラーは頻発します。

特に、文字列の中の一文字を取り出して比較するつもりが、書き方を間違えてしまうパターンです。

C++
#include <iostream>

int main() {
    const char* text = "Hello";

    // エラー:text[0]は文字(整数)だが、比較対象を"H"(文字列ポインタ)にしている
    // あるいは text == 'H' のようにポインタと文字を比較している場合も同様
    if (text[0] == "H") { 
        std::cout << "Hから始まります" << std::endl;
    }

    return 0;
}

上記の例では、text[0]の結果はchar型(整数の一種)です。

しかし、比較対象の"H"はダブルクォーテーションで囲まれているため、文字列リテラル(ポインタ)として解釈されます。

修正するには、比較対象をシングルクォーテーションで囲んで文字として扱う必要があります。

C++
#include <iostream>

int main() {
    const char* text = "Hello";

    // 修正後:シングルクォーテーションを使い、文字型同士で比較する
    if (text[0] == 'H') { 
        std::cout << "Hから始まります" << std::endl;
    }

    return 0;
}

2026年現在のモダンC++における対策

C++20やC++23、そして最新のC++26といったモダンな環境では、生のポインタを直接操作する機会を減らすことで、このような型エラーやメモリ関連のバグを未然に防ぐことが推奨されています。

ここでは、エラーを回避しつつ、より安全なコードを書くための手法を紹介します。

std::string または std::string_view の利用

Cスタイルのchar*ではなく、標準ライブラリのstd::stringを使用しましょう。

std::stringであれば、比較演算子が適切にオーバーロードされているため、直感的な記述が可能です。

また、メモリの所有権を持たない文字列参照が必要な場合は、std::string_viewが非常に効率的です。

C++
#include <iostream>
#include <string>
#include <string_view>

int main() {
    std::string str = "Modern C++";
    
    // std::stringなら文字列リテラルとも安全に比較可能
    if (str == "Modern C++") {
        std::cout << "一致しました" << std::endl;
    }

    std::string_view view = str;
    // string_viewでの安全な先頭文字チェック
    if (!view.empty() && view[0] == 'M') {
        std::cout << "先頭はMです" << std::endl;
    }

    return 0;
}

スマートポインタの活用

生のポインタ(Raw Pointer)の代わりに、std::unique_ptrstd::shared_ptrを利用することで、ポインタ操作の意図が明確になります。

スマートポインタであっても、デリファレンスを忘れるとコンパイルエラーになりますが、そのメッセージはより具体的なものになり、原因の特定が容易になります。

特に「ポインタが空であるか」を確認したい場合は、整数0と比較するのではなく、必ずnullptrを使用するように徹底してください。

nullptrはC++11から導入されたポインタ専用のリテラルであり、整数型への暗黙的な変換が行われないため、今回のようなエラーを防ぐ防波堤となります。

よくある疑問:なぜ以前のコードでは動いていたのか?

古いC言語のコードや、非常に古い規格のC++コンパイラでは、ポインタと整数の比較が警告のみで許容されることがありました。

しかし、現代のC++標準(ISO規格)では、型安全性の観点からこの挙動は明確に禁止されています。

もし古いプロジェクトを引き継いでこのエラーが出た場合は、単にエラーを消すためのキャスト(型変換)を行うのではなく、本来何を比較したかったのかを精査してください。

強引に(intptr_t)ptr == valのようにキャストしてエラーを回避することも技術的には可能ですが、それは根本的な解決ではなく、潜在的なバグを隠蔽する行為です。

必ず、変数の型を見直し、適切なデリファレンスや比較対象の修正を行うのがプロフェッショナルなアプローチです。

まとめ

「ISO C++ forbids comparison between pointer and integer」というエラーは、プログラムがメモリのアドレスと具体的な数値を混同していることを教えてくれる親切な警告です。

主な原因は「ポインタのデリファレンス忘れ」、あるいは「文字と文字列の取り違え」の二点に集約されます。

エラーを修正する際は、以下のポイントをチェックしてください。

  • ポインタの指す値を確認したい場合は、変数の前に * を付けているか。
  • 一文字を比較したい場合は ' ' (シングル)、文字列なら " " (ダブル)を正しく使い分けているか。
  • ヌルポインタのチェックには 0 ではなく nullptr を使用しているか。

最新のC++20/23/26環境では、std::stringstd::optionalなどを活用することで、ポインタを直接意識せずに済む安全な設計が可能です。

まずはエラーが発生した箇所の型を再確認し、正しい演算子が適用されているかを見直してみましょう。

型に対して厳格に向き合うことが、堅牢でメンテナンス性の高いC++コードを書くための第一歩となります。