1. 程式人生 > >gcc g++ 支援c++11編譯的標準和區別

gcc g++ 支援c++11編譯的標準和區別

g++ -g -Wall -std=c++11 main.cpp

gcc -g -Wall -std=c11 main.cpp

如果不想每次寫這個-std=C++11這個選項該怎麼辦呢?

  方法1:寫Makefile

  方法2:取別名 :alias g++11="g++ -std=c++11"

--------------------------------------------------------------------------------------------------------------------------------

一般而言,在Linux下編譯程式分為以下4個階段:

  1. 預處理:編譯處理巨集定義等巨集命令(eg:#define)——生成字尾為“.i”的檔案    
  2. 編譯:將預處理後的檔案轉換成組合語言——生成字尾為“.s”的檔案    
  3. 彙編:由彙編生成的檔案翻譯為二進位制目標檔案——生成字尾為“.o”的檔案    
  4. 連線:多個目標檔案(二進位制)結合庫函式等綜合成的能直接獨立執行的執行檔案——生成字尾為“.out”的檔案

在Linux下執行gcc與g++編譯C++檔案的差別:

  1. 字尾為.c的,gcc把它當作是C程式(cc/cpp才判定為C++源程式),而g++當作是c++程式
  2. gcc無法進行庫檔案的連線,即無法編譯完成步驟4;而g++則能完整編譯出可執行檔案。(實質上,g++從步驟1-步驟3均是呼叫gcc完成,步驟4連線則由自己完成)

  gcc -E 執行到步驟1,只處理巨集命令,需要用重定向生成檔案

  gcc -S 執行到步驟2,生成檔案.s

  gcc -c 執行到步驟3,生成檔案.o

  g++ 分別編譯於連線 .cc檔案與.o檔案

誤區一:gcc只能編譯c程式碼,g++只能編譯c++程式碼
兩者都可以,但是請注意:
1.字尾為.c的,gcc把它當作是C程式,而g++當作是c++程式;字尾為.cpp的,兩者都會認為是c++程式,注意,雖然c++是c的超集,但是兩者對語法的要求是有區別的,例如:
#include <stdio.h>
int main(int argc, char* argv[]) {
   if(argv == 0) return;
   printString(argv);
   return;
}
int printString(char* string) {
  sprintf(string, "This is a test.\n");
}
如果按照C的語法規則,OK,沒問題,但是,一旦把字尾改為cpp,立刻報三個錯:“printString未定義”;
“cannot convert `char**' to `char*”;
”return-statement with no value“;
分別對應前面紅色標註的部分。可見C++的語法規則更加嚴謹一些。
2.編譯階段,g++會呼叫gcc,對於c++程式碼,兩者是等價的,但是因為gcc命令不能自動和C++程式使用的庫聯接,所以通常用g++來完成連結,為了統一起見,乾脆編譯/連結統統用g++了,這就給人一種錯覺,好像cpp程式只能用g++似的。
 
誤區二:gcc不會定義__cplusplus巨集,而g++會
實際上,這個巨集只是標誌著編譯器將會把程式碼按C還是C++語法來解釋,如上所述,如果字尾為.c,並且採用gcc編譯器,則該巨集就是未定義的,否則,就是已定義。
 
誤區三:編譯只能用gcc,連結只能用g++
嚴格來說,這句話不算錯誤,但是它混淆了概念,應該這樣說:編譯可以用gcc/g++,而連結可以用g++或者gcc -lstdc++。因為gcc命令不能自動和C++程式使用的庫聯接,所以通常使用g++來完成聯接。但在編譯階段,g++會自動呼叫gcc,二者等價。
 
誤區四:extern "C"與gcc/g++有關係
實際上並無關係,無論是gcc還是g++,用extern "c"時,都是以C的命名方式來為symbol命名,否則,都以c++方式命名。試驗如下:
me.h:
extern "C" void CppPrintf(void);
 
me.cpp:
#include <iostream>
#include "me.h"
using namespace std;
void CppPrintf(void)
{
     cout << "Hello\n";
}
 
test.cpp:
#include <stdlib.h>
#include <stdio.h>
#include "me.h"        
int main(void)
{
    CppPrintf();
    return 0;
}
 
1. 先給me.h加上extern "C",看用gcc和g++命名有什麼不同
[

[email protected] G++]# g++ -S me.cpp
[[email protected] G++]# less me.s
.globl _Z9CppPrintfv        //注意此函式的命名
        .type   CppPrintf, @function
[[email protected] GCC]# gcc -S me.cpp
[[email protected] GCC]# less me.s
.globl _Z9CppPrintfv        //注意此函式的命名
        .type   CppPrintf, @function
完全相同!
               
2. 去掉me.h中extern "C",看用gcc和g++命名有什麼不同
[[email protected] GCC]# gcc -S me.cpp
[[email protected] GCC]# less me.s
.globl _Z9CppPrintfv        //注意此函式的命名
        .type   _Z9CppPrintfv, @function
[[email protected] G++]# g++ -S me.cpp
[[email protected] G++]# less me.s
.globl _Z9CppPrintfv        //注意此函式的命名
        .type   _Z9CppPrintfv, @function
完全相同!
【結論】完全相同,可見extern "C"與採用gcc/g++並無關係,以上的試驗還間接的印證了前面的說法:在編譯階段,g++是呼叫gcc的。

二:gcc和g++的包含標頭檔案庫檔案方法

-l引數就是用來指定程式要連結的庫,-l引數緊接著就是庫名,那麼庫名跟真正的庫檔名有什麼關係呢?就拿數學庫來說,他的庫名是m,他的庫檔名是libm.so,很容易看出,把庫檔名的頭lib和尾.so去掉就是庫名了。

好了現在我們知道怎麼得到庫名,當我們自已要用到一個第三方提供的庫名字libtest.so,那麼我們只要把 libtest.so拷貝到/usr/lib裡,編譯時加上-ltest引數,我們就能用上libtest.so庫了(當然要用libtest.so庫裡 的函式,我們還需要與libtest.so配套的標頭檔案)

放在/lib和/usr/lib和/usr/local/lib裡的庫直接用-l引數就能連結了,但如果庫檔案沒放 在這三個目錄裡,而是放在其他目錄裡,這時我們只用-l引數的話,連結還是會出錯,出錯資訊大概是:“/usr/bin/ld: cannot find -lxxx”,也就是連結程式ld在那3個目錄裡找不到libxxx.so,這時另外一個引數-L就派上用場了,比如常用的X11的庫,它在/usr /X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11引數,-L引數跟著的是庫檔案所在的目錄名。再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那連結引數就是-L /aaa/bbb/ccc -ltest

另外,大部分libxxxx.so只是一個連結,以RH9為例,比如libm.so它連結到/lib/libm.so.x,/lib/libm.so.6又連結到/lib/libm-2.3.2.so,

如果沒有這樣的連結,還是會出錯,因為ld只會找libxxxx.so,所以如果你要用到xxxx庫,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一個連結就可以了ln -s libxxxx-x.x.x.so libxxxx.so

手工來寫連結引數總是很麻煩的,還好很多庫開發包提供了生成連結引數的程式,名字一般叫xxxx-config,一般放在/usr/bin目錄下,比如

gtk1.2的連結引數生成程式是gtk-config,執行gtk-config --libs就能得到以下輸出"-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic

-lgmodule -lglib -ldl -lXi -lXext -lX11 -lm",這就是編譯一個gtk1.2程式所需的gtk連結引數,xxx-config除了--libs引數外還有一個引數是--cflags用來生成頭 檔案包含目錄的,也就是-I引數,在下面我們將會講到。你可以試試執行gtk-config --libs --cflags,看看輸出結果

現在的問題就是怎樣用這些輸出結果了,最笨的方法就是複製貼上或者照抄,聰明的辦法是在編譯命令列里加入這個 `xxxx-config --libs --cflags`,比如編譯一個gtk程式:gcc gtktest.c `gtk-config --libs --cflags`這樣就差不多了。注意`不是單引號,而是1鍵左邊那個鍵。

5、-include和-I引數

-include用來包含標頭檔案,但一般情況下包含標頭檔案都在原始碼裡用#include xxxxxx實現,-include引數很少用。-I引數是用來指定標頭檔案目錄,/usr/include目錄一般是不用指定的,gcc知道去那裡找,但 是如果標頭檔案不在/usr/include裡我們就要用-I引數指定了,比如標頭檔案放在/myinclude目錄裡,那編譯命令列就要加上-I /myinclude引數了,如果不加你會得到一個"xxxx.h: No such file or directory"的錯誤。-I引數可以用相對路徑,比如標頭檔案在當前目錄,可以用-I.來指定。
 
結論例子:

g++ curltest.cpp -o curltest -L/mnt/hgfs/windows/curl-7.19.5/lib/.libs -lcurl -I/mnt/hgfs/windows/curl-7.19.5/include

相關推薦

gcc g++ 支援c++11編譯標準區別

g++ -g -Wall -std=c++11 main.cpp gcc -g -Wall -std=c11 main.cpp 如果不想每次寫這個-std=C++11這個選項該怎麼辦呢?   方法1:寫Makefile   方法2:取別名 :alias g++11

gcc/g++以c++11編譯

pragma exp .cpp erro expect span 類定義 cte before 方法一: //在程序頭加上預定義編譯器命令 #pragma GCC diagnostic error "-std=c++11" //通過#pragma 指示 GCC編譯器處理錯誤

C++中數字與字串之間的轉換(包括C++11標準寬窄字元轉換)

1、字串數字之間的轉換 (1)string --> char *    string str("OK");    char * p = str.c_str(); (2)char * -->string    char *p = "OK";    string str(p); (3)char *

linux下安裝或升級GCC 4.8,以支援C++11標準

C++11標準在2011年8月份獲得一致通過,這是自1998年後C++語言第一次大修訂,對C++語言進行了改進和擴充。隨後各編譯器廠商都各自實現或部分實現了C++中的特性 。   如需檢視各編譯器對C++11的支援程度,請參看文章: 轉自:http://www.d

#gcc4.7.2編譯支援c++11標準,解決not a member問題

使用g++4.7.2熟悉c++11,遇到下面問題。。 'thread' isnotamemberof 'std 'yield' is not a member of 'std::this_thread' sleep_for’ is not a member of ‘st

RedHat gcc編譯器版本升級到4.8.2支援C++11標準

原來環境資訊 Red Hat Enterprise Linux Server release 6.4 (Santiago) gcc4.4.7 升級到gcc4.8.2 gcc4.8以上版本才支援C++11標準,網上很多都是裝的4.8系列的版本,

linux之讓終端支援C++11/14編譯cpp檔案

1  問題 我們的專案很多智慧指標,但是我linux的終端肯定不支援C++11/14, 我們平時都是用的下面的命令編譯c++檔案 g++ -g file.cpp -o file  r 如果是用c++11編譯需要改成如下 g++ -g -Wall -std=c+

linux下安裝或升級GCC4.8.2,以支援C++11標準[轉]

在編譯kenlm的時候需要安裝gcc, 然後還需要安裝g++。 g++安裝命令:sudo apt-get install g++ ----------------------以下為網上轉載內容,加上自己修改------------------ 本文主要介紹在Linux系統下,如何升級GCC以支援C+

CentOS上升級gcc編譯器使支援C++11

首先向博主致敬,好的東西拿來共享了,用一下不錯。 https://blog.csdn.net/clirus/article/details/62424517   0. 目標  最近在學習c++11,我本機裝的CentOS編譯器較老,不支援C++11的新特性,所以我需要把g

Ubuntu升級g++-4.8以支援C++11

也許你和我一樣在升級g++到4.8後發現用g++ a.cpp -o a還是提示編譯錯誤,那這篇文章給你答案。 轉自:http://my.oschina.net/zenglingfan/blog/169564 1. 安裝 gcc-4.8 為了使用C++ 11, 須安裝 gcc

GCC 升級4.8 支援c++11

 gcc 升級到4.8 用來支援c++11   1)cd gcc-4.8.1 , ./contrib/download_prerequisites 下載依賴   2) cd .. , mkdir gcc-build-4.8.1 , cd gcc-build-4.8.1,  

NDK編譯支援C++11

APP_CPPFLAGS += -std=c++11 // APP_CPPFLAGS += -std=gnu++11 NDK_TOOLCHAIN_VERSION=4.8 APP_STL=gnustl_

linux下安裝或升級GCC 4.8以上版本(包括),以支援C++11

本文轉載自:http://www.cnblogs.com/lizhenghn/p/3550996.html C++11標準在2011年8月份獲得一致通過,這是自1998年後C++語言第一次大修訂,對C++語言進行了改進和擴充。隨後各編譯器廠商都各自實現或部分實現了

linux下讓g++4.8.4支援C++11生效

最近在學習C++時遇到用g++編譯不支援auto型別的問題,如: 1.cpp:7:7: error: ‘a’ does not name a type   auto a=r;        ^ 後搜

配置Netbeanscodeblocks支援C++ 11

今天本來打算寫LeetCode中的。結果介面函式裡有一個unordered_set型別,編譯的時候找不著,查了一下才發現這是C++11裡的新標準類,我編譯器太老的,不支援。怎麼辦?升級編譯器唄。 NetBeans和Cygwin組合 因為習慣了NetBeans,所以編譯系

gcc -g -o -c分別是什麽意思

gcc linux-g為了調試用的 加個-g 是為了gdb 用,不然gdb用不到-o output_filename,確定輸出文件的名稱為output_filename,同時這個名稱不能和源文件同名。如果不給出這個選項,gcc就給出預設的可執行文件a.out。-E:僅執行編譯預處理; -S:將C代碼轉換為匯編

C++11中lock_guardunique_lock的區別

target san color member uri display each for clas c++11中有一個區域鎖lock_guard,還有第二個區域鎖unique_lock。 區域鎖lock_guard使用起來比較簡單,除了構造函數外沒有其他member fu

C++11】unoedered_mapmap(部分轉載)

好的 hash 比較 綜合 per 百萬 一點 應該 .net 1.結論 新版的hash_map都是unordered_map了,這裏只說unordered_map和map. 運行效率:unordered_map最高,而map效率較低但提供了穩定效率和有序的序列。 占用內存

C++11標準

weak_ptr mat clas weak 自動完成 分配內存 初始化 val decltype 1. 新類型 long long和unsigned long long; char16_t 和 char32_t; 新增原始字符串; 2. 統一的初始化 C+

gcc/g++ 連結庫的編譯與連結

 gcc/g++ 連結庫的編譯與連結 [email protected] http://blog.csdn.net/surgewong       程式編譯一般需要經預處理、編譯、彙編和連結幾個步驟。在實際應用中,有些公