C言語で発生するC2660エラーの原因と対処法について解説
C言語のプログラムをVisual Studioなどでコンパイルする際、C2660エラーが出る場合があります。
これは関数呼び出し時に指定した引数の数や型が、宣言と一致しないと発生するエラーです。
誤ったヘッダのインクルードや名前の衝突が原因の場合もあります。
解決するには、関数の定義と呼び出し箇所を再確認し、正しい引数を指定するよう修正してください。
エラー発生の基本的な内容
C2660エラーとは
C2660エラーは、関数呼び出し時に渡されたパラメーターの数や型が、関数定義と一致しない場合に発生するコンパイルエラーです。
エラーメッセージには、対象となる関数名や期待されるパラメーターの情報が含まれており、呼び出し側での不整合が原因であることを示しています。
このエラーが発生すると、プログラムは正常にコンパイルされず、関数定義と呼び出しの見直しが必要となります。
エラーメッセージに記載される内容
エラーメッセージには、以下のような情報が含まれることが多いです。
- 関数名とそのシグネチャ(例えば、func(int, int))
- 渡されたパラメーターの数や型の内容
- 異なる型や個数のパラメーターを用いた呼び出しが原因である旨の説明
例えば、「`’function’ :関数に number 個のパラメーターを指定することはできません。」といったメッセージが表示され、実際に必要なパラメーター数と異なる呼び出しが試みられていることが明示されます。
エラーの原因
関数呼び出し時のパラメーター不一致
関数呼び出し時に指定するパラメーターが、関数定義時に宣言された個数や型と異なっている場合、C2660エラーが発生します。
数や型の不一致は、プログラムの実装ミスや関数の定義変更時に見落としが生じるため、特に注意が必要です。
パラメーター個数のミスマッチ
パラメーターの個数が合致しない場合、明らかな不整合が原因となります。
下記のサンプルコードでは、func関数が2つのint型パラメーターを必要としているにもかかわらず、呼び出し時に1つしか渡していないためエラーが発生します。
#include <stdio.h>
void func(int a, int b) {
    printf("a: %d, b: %d\n", a, b);
}
int main() {
    func(1);      // エラー:必要なパラメーターが不足しています
    func(1, 2);   // 正しい呼び出し
    return 0;
}(コンパイルエラー:関数呼び出しでパラメーター数が不足しています)データ型の不一致によるエラー
関数定義時と呼び出し時で、パラメーターのデータ型が異なる場合もエラーとなります。
例えば、int型を期待している関数にdouble型が渡された場合、コンパイラが型変換を自動で行えないケースではエラーが発生します。
#include <stdio.h>
void printNumber(int num) {
    printf("Number: %d\n", num);
}
int main() {
    printNumber(3.14);   // エラー:double型をint型として扱うことはできません
    return 0;
}(コンパイルエラー:型の不一致によるパラメーターエラー)名前空間とスコープの誤用
名前空間やスコープを正しく管理しないと、グローバル関数とクラスのメンバー関数が同じ名前を持っている場合などに、意図しない関数が呼び出されエラーとなることがあります。
特に、名前空間の指定が不十分な場合、コンパイラは正しい関数シグネチャを認識できず、C2660エラーを発生させる可能性があります。
グローバル関数とメンバー関数の衝突
同じ名前の関数がグローバルスコープとクラススコープに存在する場合、呼び出し側がどちらの関数を意図しているのかが不明瞭になります。
このような場合、スコープ解決演算子::を用いてグローバル関数を明示的に指定するか、呼び出しの形式を見直す必要があります。
派生クラスによる関数隠蔽
派生クラスで新たに同名の関数を定義すると、基底クラスの関数が隠蔽されることがあります。
この場合、派生クラスのオブジェクトから基底クラスの関数を呼び出そうとすると、C2660エラーが発生することがあります。
隠蔽を回避するために、using宣言を用いて基底クラスの関数を明示的に引き継ぐ方法などが有効です。
インデックス付きプロパティおよびテンプレート利用時の注意点
C++/CLIなど、拡張構文を使用する環境では、インデックス付きプロパティやテンプレートクラスで特有の呼び出し方を誤ると、C2660エラーが発生します。
呼び出し形式の誤用
インデックス付きプロパティは、関数呼び出しの形式ではなく配列のようなブラケット構文を用いてアクセスする必要があります。
間違って関数呼び出し形式でアクセスを試みると、パラメーターの不一致とみなされエラーが発生します。
#include <msclr\marshal_cppstd.h>
using namespace System;
ref class X {
    double d;
public:
    X() : d(1.9) {}
    property double MyProp[] {
        double get(int i) { return d; }
    }
};
int main() {
    X^ MyX = gcnew X();
    // 誤った呼び出し:関数呼び出し形式
    Console::WriteLine(MyX->MyProp(1));   // C2660エラーが発生します
    return 0;
}(コンパイルエラー:インデックス付きプロパティの呼び出し形式が誤っています)テンプレートクラスでの対策
テンプレートクラス内で独自に定義した新しい演算子などは、囲い型以外の型で使用するとC2660エラーを引き起こす場合があります。
このような場合、定義内容を見直すか、適切な型を用いるように修正する必要があります。
エラーの対処法
関数定義と呼び出しの見直し
C2660エラーを解決するための基本的な対策は、関数の定義と呼び出し時のパラメーターの個数と型が一致しているかを確認することです。
関数定義を見直し、必要なパラメーターの数や型に合わせた呼び出しを行うよう修正してください。
開発環境でエラーメッセージを参照しながら、どの部分が不整合になっているのかを特定することが重要です。
名前空間およびスコープ解決演算子(::)の利用
複数のスコープに同じ名前の関数が存在する場合、スコープ解決演算子::を利用することで、明示的に対象の関数を指定することが可能です。
これにより、グローバル関数とクラスメンバー関数の衝突を回避でき、正しい関数の呼び出しを実現できます。
コード修正例の提示
メンバー関数呼び出しの修正方法
以下のサンプルコードは、クラス内のメンバー関数を正しい呼び出し形式で呼び出す方法を示しています。
#include <stdio.h>
class MyClass {
public:
    void func(int a) {
        printf("MyClass::func called with %d\n", a);
    }
};
int main() {
    MyClass obj;
    obj.func(10);   // 正しい呼び出し
    return 0;
}MyClass::func called with 10インデックス付きプロパティの正しい記述
インデックス付きプロパティは、関数呼び出しの形式ではなく配列のようなブラケット構文を利用してアクセスする必要があります。
下記の例では、正しい呼び出し方法を示しています。
#include <msclr\marshal_cppstd.h>
using namespace System;
ref class X {
    double d;
public:
    X() : d(1.9) {}
    property double MyProp[] {
        double get(int i) { return d; }
    }
};
int main() {
    X^ MyX = gcnew X();
    // 正しい呼び出し:ブラケットを使用
    Console::WriteLine(MyX->MyProp[1]);   // 正しく動作します
    return 0;
}1.9派生クラス隠蔽問題への対策
派生クラスで基底クラスの関数が隠蔽される場合、using宣言を用いることで基底クラスの関数を呼び出せるように修正します。
下記の例は、using Base::show;を使用した修正例です。
#include <stdio.h>
class Base {
public:
    void show() {
        printf("Base::show\n");
    }
};
class Derived : public Base {
public:
    using Base::show;  // 基底クラスのshow()を呼び出せるようにする
    void show(int num) {
        printf("Derived::show with %d\n", num);
    }
};
int main() {
    Derived obj;
    obj.show();      // Base::showが呼び出されます
    obj.show(5);     // Derived::showが呼び出されます
    return 0;
}Base::show
Derived::show with 5実例を用いた検証
ケーススタディ:パラメーター不一致の修正例
以下のコードは、パラメーターの個数が一致していない場合のエラーを修正した例です。
修正前はパラメーターが不足しているためエラーとなっていましたが、呼び出し側で正しい数のパラメーターを渡すことでエラーを解消できます。
#include <stdio.h>
void func(int a, int b) {
    printf("a: %d, b: %d\n", a, b);
}
int main() {
    // func(1);   // エラーとなる呼び出し(コメントアウト)
    func(5, 10);   // 正しい呼び出し
    return 0;
}a: 5, b: 10ケーススタディ:スコープ解決の適用例
次の例は、グローバル関数とクラスメンバー関数が同名の場合の修正例です。
スコープ解決演算子::を用いることで、グローバル関数を正しく呼び出す方法を示しています。
#include <stdio.h>
void printMessage() {
    printf("Global function called\n");
}
class MyClass {
public:
    void printMessage() {
        printf("Member function called\n");
    }
};
int main() {
    MyClass obj;
    obj.printMessage();      // クラス内の関数が呼び出されます
    ::printMessage();        // グローバル関数をスコープ解決演算子で呼び出します
    return 0;
}Member function called
Global function calledケーススタディ:派生クラス隠蔽問題の解消例
派生クラスで関数が隠蔽される問題の解消例です。
using宣言を用いることで、基底クラスの関数を派生クラスからも呼び出せるよう修正しています。
#include <stdio.h>
class Base {
public:
    void display() {
        printf("Base display\n");
    }
};
class Derived : public Base {
public:
    using Base::display;  // 基底クラスのdisplay()を引き継ぐ
    void display(int value) {
        printf("Derived display with %d\n", value);
    }
};
int main() {
    Derived obj;
    obj.display();       // Base::displayが呼び出されます
    obj.display(20);     // Derived::displayが呼び出されます
    return 0;
}Base display
Derived display with 20まとめ
この記事では、C2660エラーの原因と対処法について解説しました。
関数呼び出し時のパラメーターの不一致、名前空間やスコープの誤用、派生クラスによる関数隠蔽、インデックス付きプロパティやテンプレート利用時の注意点など、多角的な観点からエラー発生の要因を説明しました。
また、具体的なコード例を通じて正しい呼び出し方法や修正方法も示したため、エラーメッセージへの対処の手順と正確な修正方法が理解できる内容となっています。
