1. 程式人生 > >C++ 和 G++ 的區別

C++ 和 G++ 的區別

轉載:http://blog.csdn.net/wr_technology/article/details/53414447 

今天做題,突然遇到了一些問題,就好奇的百度了一下,看了這篇寫的蠻好的部落格。


一、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