今天做了一道水題,POJ-1004,水題一個,12個double類型的數求平均數
但是,
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 int main() { 5 double n; 6 while (cin>>n) { 7 int i=0; 8 double total = n; 9 while (i++<11) { 10 cin>>n; 11 total += n; 12 } 13 printf("$%.2lf\n", total/12); 14 } 15 return 0; 16 }
這個看起來沒毛病的代碼,竟然WA了,
又WA兩次之后,這不是代碼的事,分別用GCC,G++,C++提交,到C++的時候,A了!!!
總結總結,避免再犯
------------------------------------------------------------------------------------------------------------------------
放在最先:G++和GCC分別是C++和C的編譯器,C++和C是語言。
但POJ上的則表示你提交代碼運行所需的編譯器,C和C++對應的編譯器是VC++ 2008里面的C和C++編譯器,而GCC和G++則對應相應的編譯器。
那我上面既用了printf又用了cin怎么提交?
看到一篇博客敘述:G++和C++選項下的代碼是沒有差異的,但在庫上面,兩者有一定差距,比如G++默認可以cin一個string變量,而選擇C++時則需要#include<string>,如果用C++編寫代碼,提交時最好選擇G++作為編譯器。
不好意思,我沒用string類, 但是G++提交WA!!!
說明區別不止這一點。
------------------------------------------------------------------------------------------------------------------------
為什么G++提交WA了?
好吧回到現實中來。我昨天在做poj 3122這道題的時候,再一次的遇到了G++WA;C++AC的尷尬局面。
為什么呢?其實這個也算是編譯器優化的一部分,那就是精度缺省。
眾所周知,long long類型,作為一個在C/C++11才被確認為基本數據類型的一個數據類型,在不同的環
境下,他的類型標識符是不同的。也就是我們津津樂道的%lld 和 %I64d了。同樣,double類型也是一
個有趣的類型。double類型其實准確地說是雙精度型,他的內存長度一般是比float類型(單精度型)
的多了一倍,有的時候很早的標准里是把double稱為long float的。所以說就有了為什么float類型
用%f,double用%lf。但是由於現在不是以前的那種一個內存條就幾兆,多開一個double就會超內存的
年代了,所以double還有float在gcc中被自動優化。
在用scanf讀數據時,為了與float區分,使用%lf。
在用printf寫數據時,由於實質上,double和float是同一個類型,只不過內存占用有差異而已,他們
的標識符都是%f,注意,這個和標准C不同,這里的都是%f。
當然對於另外一個特殊的類型long double雖然不常用,但是編譯器依舊在支持,這里有個插曲,理論
上long double應該是兩倍的double(類似long long和int的關系,因為long和int其實是一個東西)
。但是實際上,long double很奇怪的是一個10字節的怪物,他有兩個空余字節,是怎么改動都不會發
生變化的。輸入輸出的標識符都是%Lf,大寫的L。
但是這里又有問題了,為什么我在本地用%f會WA,在OJ上用%f會AC?
因為我們本機如果使用的是Windows下的Code::Blocks這款IDE的話,編譯器也就是MinGW這個東西。事
實上,為了盡量保持gcc的跨平台性,MinGW在某些地方是直接用了MSVC的東西的,而對我們影響最大的
就是這個標識符的問題。簡單的說,如果你是要在本機測試,那么最好,請使用標准C的那個標識符系
統;如果你要提交代碼,那么請改成gcc的那一套標識符系統。
再有就是編譯器版本的問題,現在的MinGW版本已經到了4.8,但是POJ上仍然使4.4,所以低版本的編譯
器同樣會有一些不尋常的問題。
當然還有更簡單的方法,就是直接用輸入輸出流在控制輸入輸出,這樣更省事,而且跨平台性能更好,
不會出現這種因為標識符而出錯的情況。
列個表格出來就是這個樣子的:
列個表格出來就是這個樣子的:
double f; | POJ G++提交 | POJ C++提交 | 本機測試(MinGW GCC 4.8) | 最安全的方法 |
輸入 | scanf(“%lf”, &f); | scanf(“%lf”, &f); | scanf(“%lf”, &f); | cin >> f; |
輸出 | printf(“%f“, f); | printf(“%lf”, f); | printf(“%lf“, f); | cout << f; |
------------------------------------------------------------------------------------------------------------------------
原來還有精度的問題,那么總結:
1.用string的時候,c++需要包含頭文件:#include <string>,G++不需要
2.精度問題
3.使用GCC/G++的提醒:
對於64位整數, long long int 和 __int64 都是支持並且等價的.但是在讀和寫的時候只支持scanf("%I64d", ...)和printf("%I64d", ...).
不支持"%lld"是因為MinGW下的GCC和G++使用的msvcrt.dll動態鏈接庫並不支持C99標准.
根據ISO C++標准,在G++下,main函數的返回值必須是int,否則將會導致Compile Error(編譯錯誤)的判答
4.G++/GCC使用scanf、printf時注意引用<stdio.h>/<cstdio>,只引用<iostream>不識別