1. 程式人生 > >【C++】OJ提交題目中的語言選項裡G++與C++的區別

【C++】OJ提交題目中的語言選項裡G++與C++的區別

G++?

首先更正一個概念,C++是一門計算機程式語言,G++不是語言,是一款編譯器中編譯C++程式的命令而已。

那麼他們之間的區別是什麼?

在提交題目中的語言選項裡,G++和C++都代表編譯的方式。準確地說,選擇C++的話,意味著你將使用

的是最標準的編譯方式,也就是ANSI C++編譯。如果你使用的是G++的話,意味著你將使用GNU專案中最

平凡適用人群最多的編譯器(其實也就是我們熟悉的Code::Blocks的自帶的編譯器,Windows環境裡一

般是MinGW下的gcc,Linux中的gcc和前者基本是一個東西)進行編譯。類似的還有選擇C和GCC,前者是

標準C編譯器編譯,後者同樣是用gcc來編譯。

編譯器的差別——編譯器的優化

當然,很多時候我們有的程式碼用C++提交通過了,但是G++卻失敗了呢?眾所周知,不同的編譯器,會對

程式碼做出一些不同的優化。舉一個最簡單的例子。針對單個語句(注意,是單個語句,不是包含在語句

中的那種前++和後++):

12a:a++;b:++a;

一般的講,我們都知道,這兩條語句的最終結果是一樣的,就是a自己增加了1。但是,兩者的差距還是

有的。如果從標準C的角度去理解。a++這個語句等同於

1 a:a=a+1

也就是說,我是先呼叫,再自增。在呼叫過程中,會申請一個新的資料地址,用於存放臨時的變數

a’,然後在把a’加1,之後在把a’賦值給a。

但是++a這個語句不需要這麼麻煩。因為他是先自增,後呼叫,也就是省去了申請新地址的功夫。所以

理論上,二者的時間消耗是有差異的,如果你是使用標準C的編譯方式,就可以發現這個差異。畢竟,

申請臨時記憶體這個操作耗費的時間,遠遠比令已知記憶體的資料進行一個改變要長的多。

但是編譯器的優化就體現在了這種本身結果相同卻耗時有差異的地方。如果你使用gcc來編譯,結果你

會發現前++與後++二者基本上沒有差異。這就是編譯器的優化中的冰山一角了。事實上還有很多優化的地方。

為什麼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;

大概就是這麼多了,希望大家避免這種錯誤的發生。