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

一、OJ提交題目中的語言選項裏G++與C++的區別

http://www.th7.cn/Program/cp/201405/199001.shtml

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

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

在提交題目中的語言選項裏,G++和C++都代表編譯的方式。準確地說,選擇C++的話,意味着你將使用的是最標準的編譯方式,也就是ANSI C++編譯。如果你使用的是G++的話,意味着你將使用GNU項目中最平凡適用人羣最多的編譯器(其實也就是我們熟悉的Code::Blocks的自帶的編譯器,Windows環境裏一般是MinGW下的gcc,Linux中的gcc和前者基本是一個東西)進行編譯。類似的還有選擇C和GCC,前者是標準C編譯器編譯,後者同樣是用gcc來編譯。

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

當然,很多時候我們有的代碼用C++提交通過了,但是G++卻失敗了呢?衆所周知,不同的編譯器,會對代碼做出一些不同的優化。舉一個最簡單的例子。針對單個語句(注意,是單個語句,不是包含在語句中的那種前++和後++):

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

一般的講,我們都知道,這兩條語句的最終結果是一樣的,就是a自己增加了1。但是,兩者的差距還是有的。如果從標準C的角度去理解。a++這個語句等同於

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的那一套標識符系統。

當然還有更簡單的方法,就是直接用輸入輸出流在控制輸入輸出,這樣更省事,而且跨平臺性能更好,不會出現這種因爲標識符而出錯的情況。

列個表格出來就是這個樣子的:

double f; G++提交 C++提交 本機gcc測試 最安全的方法
輸入 scanf("%lf", &f); scanf("%lf", &f); scanf("%lf", &f); cin >> f;
輸出 printf("%f", f); printf("%lf", f); printf("%lf", f); cout << f;

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


二、手動擴大棧內存,讓AC無憂

http://blog.csdn.NET/shahdza/article/details/6586430

還在因爲 怕 g++ 提交時間很慢,但是用C++ 交又怕棧溢出???

我們都知道,如果代碼裏有 遞歸函數 頻繁調用, 用 C++ 提交代碼, 很可能就會 出現

     Runtime Error           
(ACCESS_VIOLATION) 

但是用G++提交,如果數據量很多的話,又會出現

  Time Limit Exceeded

那怎麼辦呢???

呵呵,G++的話可以用輸入加速外掛啦~~~,以前我介紹過的。 

同樣的C++也可以防止棧溢出!!!

只要在你的代碼里加上下面這句話, OK,棧溢出直接搞定!!!

#pragma comment(linker, "/STACK:102400000,102400000")



三、oj 中G++和C++區別

原創在這裏 http://www.cnblogs.com/dongsheng/archive/2012/10/22/2734670.html

1、輸出double類型時,如果採用G++提交,scanf採用%lf,prinf採用%f,否則會報錯

2、使用GCC/G++的提醒:

對於64位整數, long long int 和 __int64 都是支持並且等價的.但是在讀和寫的時候只支持scanf("%I64d", ...)和printf("%I64d", ...).不支持"%lld"是因爲MinGW下的GCC和G++使用的msvcrt.dll動態鏈接庫並不支持C99標準. (杭電OJ G++支持"%lld"
根據ISO C++標準,在G++下,main函數的返回值必須是int,否則將會導致Compile Error(編譯錯誤)的判答

3、G++/GCC使用scanf、printf時注意引用<stdio.h>,只引用<iostream>不識別 (杭電OJ G++不需要<stdio.h>



補充:

__int64與long long 都是在32位平臺開始使用的64位整數的數據類型,在存儲方式和使用方式上沒有區別。
兩者的區別在於,它們命名的發起人不同,支持的平臺不同。long long這個數據類型,是UNIX平臺發起並支持的,而__int64是微軟從win95(VC6)開始發起並支持的,在老的windows開發平臺下(如VC6),不識別long long,而老的UNIX,也不識別_int64。當然,現在比較新的平臺,兩種數據格式和相關的定義、函數都可以兼容了。

同樣,作爲64位整數的printf輸出格式定義,也是一樣,微軟使用的是%i64d,而UNIX使用的是%lld以及%llu(無符號64位)等形式。

實際上,無論哪一種,在實際效果上沒有不同,只是因爲定義者和使用環境造成的支持或不支持的問題。
而ACM中,編譯識別系統偏向更多的支持微軟系統的定義,因此應該使用__int64和%i64d

發佈了100 篇原創文章 · 獲贊 46 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章