今天在調試一段程式,輸出結果總是錯誤,不知道什麼原因,代碼如下:
#include <sstream><br />#include <iostream><br />#include <netinet/in.h><br />#include <arpa/inet.h><br />using namespace std;<br />void print_address(struct in_addr addr1, struct in_addr addr2)<br />{<br />ostringstream oss;<br />oss << inet_ntoa(addr1) << "|" << inet_ntoa(addr2);<br />cout << oss.str() << endl;<br />}<br />int main()<br />{<br />struct in_addr addr1, addr2;<br />inet_aton("10.0.0.1", &addr1);<br />inet_aton("10.0.0.2", &addr2);<br />print_address(addr1, addr2);<br />return 0;<br />}
本來以為程式會輸出:
10.0.0.1|10.0.0.2
可是卻大出所料,輸出的結果為:
10.0.0.1|10.0.0.1
非常奇怪,故把代碼修改為以下,以作測試:
void print_address(struct in_addr addr1, struct in_addr addr2)<br />{<br />ostringstream oss;<br />oss << inet_ntoa(addr1) << "|" << inet_ntoa(addr2);<br />cout << oss.str() << endl;<br />cout << inet_ntoa(addr1) << endl;<br />cout << inet_ntoa(addr2) << endl;<br />}
輸出還是非常奇特:
10.0.0.1|10.0.0.1<br />10.0.0.1<br />10.0.0.2
非常不解,難道是oss的問題還是其他?於是把代碼修改如下:
void print_address(struct in_addr addr1, struct in_addr addr2)<br />{<br />ostringstream oss;<br />oss << inet_ntoa(addr1) << "|" ;<br />oss << inet_ntoa(addr2);<br />cout << oss.str() << endl;<br />cout << inet_ntoa(addr1) << endl;<br />cout << inet_ntoa(addr2) << endl;<br />}
此時,程式奇怪的輸出了我想要的結果:
10.0.0.1|10.0.0.2<br />10.0.0.1<br />10.0.0.2
通過以上輸出結果,我大致猜到了原因,此時在源碼中添加以下代碼:
void print_address(struct in_addr addr1, struct in_addr addr2)<br />{<br />ostringstream oss;<br />oss << inet_ntoa(addr1) << "|" ;<br />oss << inet_ntoa(addr2);<br />cout << oss.str() << endl;<br />printf("%p %p/n", inet_ntoa(addr1), inet_ntoa(addr2));<br />printf("%p/n", inet_ntoa(addr1));<br />}
正如我所料,程式輸出:
10.0.0.1|10.0.0.2<br />0x7fed7533b6b8 0x7fed7533b6b8<br />0x7fed7533b6b8
此時可以確定了我的猜測:
oss << inet_ntoa(addr1) << "|" << inet_ntoa(addr2);在啟動並執行時候,首先執行inet_ntoa(addr2),得到一個函數指標,假設是p1;然後執行inet_ntoa(addr1),得到另一個指標,假設是p2,然後整個語句執行oss << p1 << "|" << p2;得到最後結果。問題就在這裡,其實p1, p2的值是相等的,也就是說,他們指向同一塊記憶體位址,而該段地址空間記憶體放的資料為最後一次執行inet_ntoa()時的結果。在加上oss語句是從右向左開始執行的,於是,在執行oss << p1 << "|" << p2;的時候,其實是執行了:oss << p1 << "|" << p1;於是oss中便存放了兩個相同的IP地址。
細想一下,系統開發人員這樣設計也有他自己的道理。由於inet_ntoa()函數調用是不需要使用者手動分配記憶體空間的,這樣系統就必須為這個操作分配足夠的空間。如果每一次執行該函數都分配一次空間,而使用者又沒有釋放,或者系統釋放了一次,然後使用者又釋放一次,這樣都會產生記憶體流失。所以,乾脆開發人員便開闢一段記憶體空間,每次調用都使用相同記憶體,在進程結束的時候由系統收回記憶體,如此既不浪費,也不需要使用者作繁瑣的操作。
但是還有一個問題,如果使用者手動對該記憶體段進行釋放,也會出現問題,所以建議大家不要使用類似函數,而使用使用者可以自訂記憶體位址的函數,而在這裡,inet_ntoa()函數對應的函數則為inet_ntop()。