C與C++函式的不同特性

zenny_chen發表於2007-10-09

        C與C++函式最大的不同點在於——C++函式可以過載,即幾個函式的函式名可以相同,但是引數型別或引數個數必須不同;而C函式在一個環境中不能同名。這其中可以引申出關於為什麼C++的型別安全機制比C更好的原因。先請看下面的程式碼:

 

// a.c

#include 
<stdio.h>


void Hi(void)
{
    puts(
"Hi");
}



void test(void)
{
    
void *= &Hi;
    
    (
*(void(*)(void))p)();
}

         上面是一段C程式碼。我們可以看到test()函式中有一個void指標指向Hi函式,這不會有任何問題(沒有error和warning)。

        下面再看一段C++程式碼:

 

#include <iostream>
using namespace std;


void Hello(void)
{
    cout 
<< "Hello, world!" << endl;
}



void Hello(int i)
{
    cout 
<< "The data is: " << i << endl;
}



extern "C" void test(void);

int main(void)
{
    
void(*p)(void= &Hello;
    
    (
*p)();
    
    
void *= (void*)(unsigned long)(void(*)(int))&Hello;
    
    (
*(void(*)(int))q)(10);
    
    test();
    
    
return 0;
}


 

        我們看到這段程式碼中有兩個Hello()函式,一個帶有一個型別為void的引數,而另一個帶有一個型別為int的引數。我們看main()函式的第一句:void(*p)(void= &Hello;這句語句沒有問題。因為C++編譯器與C編譯器不同,在這種情況下,編譯器將根據左運算元的型別去跟有運算元的型別進行比較,因為Hello()函式集合中確實存在(void(*)(void))型別的函式,因此匹配成功。

        如果是void *p = &Hello;那麼編譯器肯定出錯。我們可以簡單地理解為編譯器無法識別所取的Hello函式的地址到底是哪一個。其實利用上述思路我們應該正確地理解為:由於編譯器無法在Hello集合中找到void*型別與左運算元的型別進行匹配,所以編譯器會報錯。

        解決這個問題的方法就是通過多次的型別強制轉換。這裡還有一個GCC系列編譯器的問題。該系列的編譯器規範指出,void*型別的指標不能指向函式,因此如果單純地強制轉為(void(*)(int))編譯器會有warning,所以這裡先轉為(void(*)(int)),然後再轉為(unsigned long),最後再轉為(void*),這樣就不會產生warning。

        而C語言編譯器不會有型別查詢,它直接比較左運算元和有運算元的型別一致性問題,並且放得很寬。

相關文章