国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

二三、編譯器

這篇具有很好參考價值的文章主要介紹了二三、編譯器。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

二三、編譯器

1、One Definition Rule

1)轉化單元

我們寫好的每個源文件(.cpp,.c)將其所包含的頭文件(#include <xxx.h>)合并后,稱為一個轉化單元。

編譯器單獨的將每一個轉化單元生成為對應的對象文件(.obj),對象文件包含了轉化單元的機器碼和轉化單元的引用信息(不在轉化單元中定義的對象)。

最后鏈接器將各個轉化單元的對象文件鏈接起來,生成我們的目標程序。

比如在對象文件A中包含了定義在其它轉化單元的引用,那么就去其它轉化單元的對象文件中尋找這個引用的定義來建立鏈接,如果在所有的對象文件中都找不到這個定義,那么就會生成一個鏈接錯誤。

2)未定義行為

在編寫代碼中,C++標準未做規(guī)定的行為,稱為未定義行為,未定義行為的結果是不確定的,具體不同的編譯器下會有不同的效果,比如

c=2*a++ + ++a*6;

這里先算a++還是先算++a就是一個未定義行為,比如

int x = -25602;

x= x>>2;

x的結果在不同的編譯器下是不確定的,因為這也屬于未定義行為

3)One Definition Rule(ODR)

ODR是一系列規(guī)則,而不是一個規(guī)則,程序中定義的每個對象都應有著自己的規(guī)則;但是基本上來講任何的變量、函數、類、枚舉、模板、概念(C++20)在每個轉化單元中都只允許有一個定義;

在整個程序中,非inline的函數或變量(C++17),有且僅能有一個定義

const聲明的變量或函數只在當前的源文件中有效,可以在一個項目的不同源文件定義相同的const變量

4)名稱的鏈接屬性

程序中的變量、函數、結構等都有著自己的名字,這些名字具有不同的鏈接屬性,鏈接器就是根據這些鏈接屬性來把各個對象文件鏈接起來的。鏈接屬性分為以下三種

①內部鏈接屬性:該名稱僅僅在本轉化單元中有效,如static、const聲明的變量、函數

②外部鏈接屬性:該名稱在其它轉化單元中也有效。通過extern關鍵字可以定義外部鏈接屬性

③無鏈接屬性:該名稱僅僅能夠用于該名稱的作用域內訪問

注:static變量或函數在自己的轉化單元有著自己的內存空間,而inline定義的變量只有一個內存地址

2、#define

1)用法一

#define A B          //將標識符A定義為B的別名

#define 整數 int        //將整數替換為int
整數 a{};
//#define實際用法
#include <iostream>
#define _HHHH_ int a  //將_HHHH_ 替換為int a
#define VERSION "V2.0"
int main()
{
	_HHHH_ { 250 };
	std::cout << a << std::endl;
	std::cout << VERSION<<std::endl;
}

2)C++中定義常量的方式

//C++定義常量的方法
const int width{1080};

//C語言中經常通常#define來定義常量
#define width 1080
#define的方式來定義常量存在一個問題,有時候并不安全

3)#define其它寫法

#define H  //定義一個標識符H ,代碼中的H將會被刪除掉
int H a 相當于 int a;

//實際場景應用
#define _in_            //沒有實際意義
#define _out_ 
int ave(_in_ int a,_out_ int& b)
{
    return a+b
}

4)取消宏的定義

//語法
#undef H   //

//應用場景
#define _H_
#undef _H_    //刪除宏_H_的定義,后面的代碼不能使用

注:執(zhí)行順序為代碼編譯的順序(從上到下),而不是函數調用的順序

5)定義復雜表達式宏

#define SUM(X,Y) X+Y                 //使用X+Y替換SUM(X,Y)
#define AVE(X,Y) (X+Y)/2             //使用(X+Y)/2替換AVE(X,Y)
#define BIGGER(X,Y) ((X)>(Y)?(X):(Y))

SUM(100,200);
AVE(100,200);
BIGGER(100,200);

//實際應用場景
#define RELEASE(x) delete[] x;x=nullptr

int main()
{
    int* a  = new int[50];
    RELEASE(a);
}

6)定義復雜表達式宏

// #可以將一個標識符參數字符串化
#define SHOW(X) std::cout<<#X          //通過#將X處理成了字符串
SHOW(1234fg);      //相當于std::cout<<"12345fg"

// ##可以連接兩個標識符
#define T1(X,Y) void X##Y(){std::cout<<#Y;}
T1(test, 22);
3、namespace

有時候為了方便管理,把相關的函數、變量、結構體等會附加到一個命名空間中

//聲明命名空間
namespace t
{
    int value;
}
//訪問這個命名空間的變量
t::value

//直接使用命名空間,不推薦
using namespace t;
vlaue=255;

2)全局命名空間

雖有具有鏈接屬性的對象,只要沒有定義命名空間,就默認定義在全局命令空間中,全局命名空間中成員的訪問不用顯示的指定,當局部名稱覆蓋了全局名稱時才需要顯示的指定全局命令空間

int a;
::a=250;

3)命名空間的擴展

//第二個htd屬于對htd命名空間的擴展,weight和heigth同屬于一個命名空間
namespace htd
{
    int weigth{1980};
}
namespace htd
{
    int heigth{1080};
}

4)命名空間的聲明

//htd.h
namespace std
{
    extern int height;      //變量聲明
    void test();            //函數聲明
}

//htd.cpp
#include <iostream>
#include "htd.h"

int htd::heigth{250};      //變量定義
void htd::test()          //函數定義
{
    std::cout<<htd::height;
}

5)命名空間的嵌套

//htd.h
namespace htd
{
    namespace hack               //命名空間的嵌套
    {
        void hackServer();
    }
    
}

//htd.cpp
void htd::hack::hackServer()
{
    ...
}
void htd::sendSms()
{
    ...
}

6)未命名的命名空間

? 不給命名空間指定名稱,將會聲明一個未命名的命名空間。未命名的命名空間中聲明的內容一律為內部鏈接屬性,包括extern聲明的內容,未命名的命名空間僅僅在本轉化單元中有效

//t.cpp
void THack()
{
    
}
//x.cpp
namespace
{
    void THack()
	{
    
	}
}	
int main()
{
    THack();
}
//

7)命名空間的別名

namespace htd
{
    void sendSms();
    namespace hack
    {
        void hackServer();
    }
}
namespace hServer=htd::hack;
hServer::hackServer();
4、預處理指令邏輯

所有#開頭的代碼都是和編譯器進行打交道

1)#ifdef

#define _HEIGHT_ 1080       //#ifdef和#endif成對出現(xiàn)
#ifdef _HIGHT_
#else
#endif


//hc.h
#ifdef _HC_        //如果定義了宏_HC_,就執(zhí)行XXXX里面的代碼。如果沒有定義,則執(zhí)行YYYYY
XXXX
#else
YYYYY
#endif

//常見用法
#ifndef _HC_     //如果沒有定義了宏_HC_
#define _HC_     //則定義了宏_HC_
#else
#endif
//實際應用場景
#ifdef UNICODE     //如果使用了UNICODE字符集,則使用wchar_t定義變量
wchar_t a;
#else
char a;
#endif

二三、編譯器

//通過預處理指令進行版本控制
#define VERSION 101

#if VERSION==100           //當VERSION為100時,執(zhí)行如下邏輯,否則執(zhí)行else中的邏輯
	void SendSms()
    {
        
    }
#else
	void SendSms()
    {
        
    }
#endif 

2)#elif

//#elif語法
#define _HEIGHT_ 2080
#if _HEIGHT_ == 1080          //針對每一個分辨率執(zhí)行不同的邏輯
...
#elif _HEIGHT_ == 720
...
#else
...
#endif
    
//預處理指令可以進行簡單的計算//當VERSION為100時,執(zhí)行如下邏輯,否則執(zhí)行else中的邏輯
	void SendSms()
    {
        
    }
5、預定義宏

1)標準預定義標識符_fun_

編譯器支持ISO C99和ISO C++ 11,即可使用該預定義標識符。用于返回函數的名稱

__func__   //返回函數的名稱

//用法示例
#include <iostream>

int main()
{
	std::cout << __func__ << std::endl;     //返回函數名稱,輸出main
}

2)標準預定義宏

編譯器支持ISO C99和ISO C++17標準,即可使用以下預定義宏

說明
_DATE_ 返回源文件的編譯日期
_TIME_ 返回當前轉化單元的轉化時間(可理解為代碼修改的時間)
_FILE_ 返回源文件的名稱
_LINE_ 返回當前的行
__cplusplus 當當前單元為C++時(即.cpp文件時),__cplusplus定義為一個整數,否則不是c++文件
#include <iostream>

int main()
{
	std::cout << __func__ << std::endl;     //返回函數名稱,輸出main
	std::cout << __DATE__ << std::endl;
	std::cout << __TIME__ << std::endl;
	std::cout << __FILE__ << std::endl;
	std::cout << __LINE__ << std::endl;
	std::cout << __cplusplus << std::endl;
}

二三、編譯器

3)MSVC的預定義宏(可理解為微軟的VC編譯器中,預定義的一些宏)

說明
_CHAR_UNSIGNED 如果char類型為無符號,該宏定義為1,否則為未定義
_COUNTER_ 用于計數,從0開始,每使用一次都會遞增1
_DEBUG 如果設置了_DEBUG宏,代表當前為調試狀態(tài)/lDd /mDd /mTd該宏定義為1,否則為未定義
_FUNCTION_ 返回函數名稱 ,但是不包含修飾名
_FUNCDNAME_ 函數名稱 包含修飾名
_FUNCSIG_ 包含了函數簽名的函數名
_WIN32 當編譯為32位ARM,64位ARM,X68或X64定義為1,否則未定義
_WIN64 當編譯為64位ARM或x64定義為1,否則未定義。用于區(qū)別
_TIMESTAMP_ 最后一次源代碼修改的時間和日期
#include <iostream>

int main()
{
#ifdef _CHAR_UNSIGNED  //如果char為無符號類型,可以通過該預定義宏進行檢驗
	std::cout << "無符號類型";
#endif
	std::cout << "有符號類型" << std::endl;
	std::cout << __COUNTER__ << std::endl;   //代表計數
	std::cout << __COUNTER__ << std::endl;
	std::cout << __COUNTER__ << std::endl;
#ifdef _DEBUG       //代表調試狀態(tài)
	std::cout << "調試狀態(tài)" << std::endl;
	std::cout << __FUNCTION__ << std::endl;  //返回函數名,不包含修飾名
	std::cout << __FUNCDNAME__ << std::endl; //返回函數名,包含修飾名
	std::cout << __FUNCSIG__ << std::endl;  //包含函數簽名,即調用、約定等信息
	std::cout << __TIMESTAMP__ << std::endl; //最后一次源代碼修改的時間和日期

#endif
#ifdef _WIN32  //用于區(qū)分Win32架構或者Win64架構
	std::cout << "X86" << std::endl;
#endif // _WIN32

}

只要【項目屬性】-【C/C++】-【代碼生成】-【運行庫】,選擇了調試,則_DEBUG就會顯示

二三、編譯器

二三、編譯器

注:上述宏只在微軟的VS編輯器才可以使用,其它的編譯器無法使用

6、調試

? 我們編寫好程序以后,可能存在一些bug和錯誤,對于語法上錯誤,編譯器能夠直接給出提示,而對于邏輯上的錯誤,編譯器不能夠直接發(fā)現(xiàn),調試就是一個找錯誤和改錯誤的過程

1)調試建議:為了方便調試,在編程風格上提出如下建議

①功能能模塊化就模塊化

②使用能夠體現(xiàn)出具體意義的函數名和變量名

③使用正常的縮進和代碼塊

④良好的注釋習慣

2)利用集成調試器調調試程序

VS2019繼承了一個調試器,可以利用斷點、流程跟蹤等方式來調試自己的程序

斷點就是當程序執(zhí)行到斷點位置,程序就會停下來

3)利用其它調試器

OllyDbg

X96Dbg

WinDbg

4)利用預處理指令來輸出調試信息

#define _dbg_i    //先定義一個宏

#ifdef _dbg_i    //如果宏存在,則執(zhí)行下面的代碼塊
	std::cout<<"調試信息";
#endif
7、assert

assert宏需要頭文件cassert

1)assert語法

//assert語法
assert(bool表達式);   //如果括號內的bool表達式為false,則會調用std::abort()函數,彈出下面的對話框,

二三、編譯器

2)關閉assert

//關閉assert
#define NDEBUG  //可以在當前轉化單元關閉assert,但是這個定義必須放在#include <cassert>之前

3)static_assert(靜態(tài)斷言)文章來源地址http://www.zghlxwxcb.cn/news/detail-760377.html

//static_assert用于編譯時檢查條件
static_assert(bool表達式,"Error information");   //先檢查表達式,若表達式為假,則輸出后面的錯誤信息。如果表達式為0,則程序是不進行編譯的,此處二點bool表達式只能用于常量

//C++17新語法
static_assert(bool表達式);

到了這里,關于二三、編譯器的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 前端框架編譯器之模板編譯

    前端框架編譯器之模板編譯

    編譯原理:是計算機科學的一個分支,研究如何將 高級程序語言 轉換為 計算機可執(zhí)行的目標代碼 的技術和理論。 高級程序語言:Python、Java、JavaScript、TypeScript、C、C++、Go 等。 計算機可執(zhí)行的目標代碼:機器碼、匯編語言、字節(jié)碼、目標代碼等。 編譯器 (Compiler):是一種將

    2024年04月28日
    瀏覽(25)
  • 【C語言】--編譯及編譯器

    【C語言】--編譯及編譯器

    夫學須靜也,才須學也;非學無以廣才,非志無以成學 個人主頁:【??個人主頁】 系列專欄:【??系列專欄】 C語言一直以來都是初入編程的小白們的必修課,作為程序員必學語言之一,C語言自然有屬于它的奧秘,接下來就由我來帶領大家走進C語言的世界吧?????? 1、

    2024年02月13日
    瀏覽(27)
  • 編譯原理課程設計--C語言編譯器

    編譯原理課程設計--C語言編譯器

    源程序1: 源程序1詞法分析結果: 與程序1語法分析結果(部分) 源程序1四元式: 源程序1優(yōu)化后的四元式: action-goto表(部分) 文件目錄: (1)掌握語義分析過程,即語法制導翻譯過程。 (2)在語法分析的LR分析程序中的基礎上添加程序,進行語義分析,生成源程序的四

    2024年02月08日
    瀏覽(30)
  • openharmony 編譯LLVM編譯器基礎架構

    third_party_llvm-project: 管理員 liwentao_uiw dhy308 huanghuijin (1) 缺少依賴,一次安裝好幾個依賴 (2) case in的語法識別不了 實際上case in是沒有問題的,主要是結尾需要改成Unix結尾

    2024年01月19日
    瀏覽(31)
  • 【Linux工具】編譯器、調式器、項目自動化構建工具以及git的使用(1編譯器)

    【Linux工具】編譯器、調式器、項目自動化構建工具以及git的使用(1編譯器)

    作者:愛寫代碼的剛子 時間:2023.6.3 本篇博客主要詳細介紹Linux中十分重要的工具:編譯器,靈活使用這些工具是Linux中一項必備技能。項目自動化構建工具、調式器、git工具會在下一篇博客中進行介紹。 Linux編譯器-gcc/g++使用 gcc編譯C語言: g++編譯C++: gcc只能編譯C語言,而

    2024年02月09日
    瀏覽(21)
  • 【linux】編譯器使用

    【linux】編譯器使用

    目錄 1. gcc ,g++ 編譯器使用 a. 有關gcc的指令(g++同理) 2. .o 文件和庫的鏈接方式 a. 鏈接方式 b. 動態(tài)庫 和 靜態(tài)庫 優(yōu)缺點對比 c. debug 版本 和 release 版本 注意: linux下自帶gcc編譯器,如果要安裝g++編譯器; sudo yum install -y gcc-g++ (普通用戶) gcc + 文件名 得到可執(zhí)行文件 gcc + 文

    2024年04月26日
    瀏覽(28)
  • 交叉編譯器介紹

    簡介 ? 要在 X86 的電腦上編譯出能夠在 Arm 上運行的程序,我們必須明確告訴編譯器,編譯生成的可執(zhí)行文件需要以 Arm 指令集的標準編碼。開發(fā)者們?yōu)椴煌男酒_發(fā)了不同的編譯器,比如針對 Arm 平臺的 arm-linux-gcc,針對 mips 平臺的 mips-linux-gnu-gcc,這些編譯器都是基于 G

    2024年02月06日
    瀏覽(32)
  • 提速Rust編譯器!

    提速Rust編譯器!

    Nethercote是一位研究Rust編譯器的軟件工程師。最近,他正在探索如何提升Rust編譯器的性能,在他的博客文章中介紹了Rust編譯器是如何將代碼分割成代碼生成單元(CGU)的以及rustc的性能加速。 他解釋了不同數量和大小的CGU之間的權衡以及Rustc是如何使用LLVM并行化代碼生成和優(yōu)

    2024年02月13日
    瀏覽(19)
  • MSVC編譯器介紹

    MSVC編譯器介紹

    與Linux系列操作系統(tǒng)不同,Windows原生環(huán)境不提供類似 gcc , Clang 的C/C++語言 源程序編譯運行工具鏈 。運行在Windows上的IDE(集成開發(fā)環(huán)境),比如CodeBlocks之類,一般都使用 MinGW ( Minimalist GNU for Windows ) 配置模擬Linux下的開發(fā)環(huán)境來進行Windows下的開發(fā)。 但是 在Windows下,與開

    2024年02月02日
    瀏覽(20)
  • Python 編譯器

    什么是編譯器 Python 編譯器的發(fā)展歷程 Python 編譯器的類型 常見的 Python 編譯器 如何選擇 Python 編譯器 Python Logo 編譯器是將源代碼轉換成可執(zhí)行代碼的程序。Python 作為一門高級編程語言,需要借助編譯器將代碼轉換成機器語言,以便計算機識別并執(zhí)行。 早期版本的 CPython 解釋

    2024年02月11日
    瀏覽(49)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包