當前位置:首頁 » 編程軟體 » 編譯器折疊方法

編譯器折疊方法

發布時間: 2023-08-11 15:41:22

❶ 現代C/C++編譯器有多智能

最近在搞C/C++代碼的性能優化,發現很多時候自以為的優化其實編譯器早就優化過了,得結合反匯編才能看出到底要做什麼樣的優化。
請熟悉編譯器的同學結合操作系統和硬體談一談現代c/c++編譯器到底有多智能吧。哪些書本上的優化方法其實早就過時了?
以及程序員做什麼會讓編譯器能更好的自動優化代碼?
舉個栗子:
1,循環展開,大部分編譯器設置flag後會自動展開;
2,順序SIMD優化,大部分編譯器設置flag後也會自動優化成SIMD指令;
3,減少中間變數,大部分編譯器會自動優化掉中間變數;
etc.
查看代碼對應的匯編:
Compiler Explorer
【以下解答】
舉個之前看過的例子:
int calc_hash(signed char *s){ static const int N = 100003; int ret = 1; while (*s) { ret = ret * 131 + *s; ++ s; } ret %= N; if (ret < 0) ret += N; //注意這句 return ret;}
【以下解答】
舉個簡單例子,一到一百求和
#include int sum() { int ret= 0; int i; for(i = 1; i <= 100; i++) ret+=i; return ret;}int main() { printf("%d\n", sum()); return 0;}
【以下解答】
話題太大,碼字花時間…
先放傳送門好了。
請看Google的C++編譯器組老大Chandler Carruth的演講。這個演講是從編譯器研發工程師的角度出發,以Clang/LLVM編譯C++為例,向一般C++程序員介紹理解編譯器優化的思維模型。它講解了C++編譯器會做的一些常見優化,而不會深入到LLVM具體是如何實現這些優化的,所以即使不懂編譯原理的C++程序員看這個演講也不會有壓力。
Understanding Compiler Optimization - Chandler Carruth - Opening Keynote Meeting C++ 2015
演示稿:https://meetingcpp.com/tl_files/mcpp/2015/talks/meetingcxx_2015-understanding_compiler_optimization_themed_.pdf
錄像:https://www.youtube.com/watch?v=FnGCDLhaxKU(打不開請自備工具…)
Agner Fog寫的優化手冊也永遠是值得參考的文檔。其中的C++優化手冊:
Optimizing software in C++ - An optimization guide for Windows, Linux and Mac platforms - Agner Fog
要稍微深入一點的話,GCC和LLVM的文檔其實都對各自的內部實現有不錯的介紹。
GCC:GNU Compiler Collection (GCC) Internals
LLVM:LLVM』s Analysis and Transform Passes
========================================
反模式(anti-patterns)
1. 為了「優化」而減少源碼中局部變數的個數
這可能是最沒用的手工「優化」了。特別是遇到在高級語言中「不用臨時變數來交換兩個變數」這種場景的時候。
看另一個問題有感:有什麼像a=a+b;b=a-b;a=a-b;這樣的演算法或者知識? - 編程
2. 為了「優化」而把應該傳值的參數改為傳引用
(待續…)
【以下解答】
推薦讀一讀這里的幾個文檔:
Software optimization resources. C++ and assembly. Windows, Linux, BSD, Mac OS X
其中第一篇:http://www.agner.org/optimize/optimizing_cpp.pdf
講解了C++不同領域的優化思路和問題,還有編譯器做了哪些優化,以及如何代碼配合編譯器優化。還有優化多線程、使用向量指令等的介紹,推薦看看。
感覺比較符合你的部分需求。
【以下解答】
一份比較老的slides:
http://www.fefe.de/source-code-optimization.pdf
【以下解答】
利用C++11的range-based for loop語法可以實現類似python里的range生成器,也就是實現一個range對象,使得
for(auto i : range(start, stop, step))
【以下解答】
我覺得都不用現代。。。。寄存器分配和指令調度最智能了
【以下解答】
每次編譯poco庫的時候我都覺得很為難GCC
【以下解答】
有些智能並不能保證代碼變換前後語義是等價的
【以下解答】
誒誒,我錯了各位,GCC是可以藉助 SSE 的 xmm 寄存器進行優化的,經 @RednaxelaFX 才知道應該添加 -march=native 選項。我以前不了解 -march 選項,去研究下再來補充為什麼加和不加區別這么大。
十分抱歉黑錯了。。。以後再找別的點來黑。
誤導大家了,實在抱歉。(??ˇ?ˇ??)
/*********以下是並不正確的原答案*********/
我是來黑 GCC的。
最近在搞編譯器相關的活,編譯OpenSSL的時候有一段這樣的代碼:
BN_ULONG a0,a1,a2,a3; // EmmetZC 註:BN_ULONG 其實就是 unsigned longa0=B[0]; a1=B[1]; a2=B[2]; a3=B[3];A[0]=a0; A[1]=a1; A[2]=a2; A[3]=a3;
【以下解答】
提示:找不到對象
【以下解答】
忍不住抖個機靈。
私以為正常寫代碼情況下編譯器就能優化,才叫智能編譯器。要程序員絞盡腦汁去考慮怎麼寫代碼能讓編譯器更好優化,甚至降低了可讀性,那就沒有起到透明屏蔽的作用。
智能編譯器應該是程序猿要較勁腦汁才能讓編譯器不優化。
理論上是這樣的。折疊我吧。
【以下解答】
編譯器智能到每次我都覺得自己很智障。
【以下解答】
雖然題主內容里是想問編譯器代碼性能優化方面的內容,但題目里既然說到編譯器的的智能,我就偏一下方向來說吧。
有什麼更能展示編譯器的強大和智能?
自然是c++的模版元編程
template meta programming
簡單解釋的話就是寫代碼的代碼,寫的還是c++,但能讓編譯器在編譯期間生成正常的c++代碼。
沒接觸過的話,是不是聽上去感覺就是宏替換的加強版?感覺不到它的強大呢?
只是簡單用的話,效果上這樣理解也沒什麼
但是一旦深入下去,尤其翻看大神寫的東西,這明明看著就是c++的代碼,但TM怎麼完全看不懂他在干什麼?後來才知道這其實完全是另外一個世界,可是明明是另外一個世界的東西但它又可以用來做很多正常c++能做的事....
什麼?你說它好像不能做這個,不能做那個,好像做不了太多東西,錯了,大錯特錯。就像你和高手考試都考了100分的故事一樣,雖然分數一樣,但你是努力努力再努力才得了滿分,而高手只是因為卷面分只有100分.....在元編程面前,只有想不到,沒有做不到。
再回頭看看其他答案,編譯器順手幫你求個和,丟棄下無用代碼,就已經被驚呼強大了,那模板元編程這種幾乎能在編譯期直接幫你「生成」包含復雜邏輯的c++代碼,甚至還能間接「執行」一些復雜邏輯,這樣的編譯器是不是算怪獸級的強大?
一個編譯器同時支持編譯語法相似但結果不同卻又關聯的兩種依賴語言,這個編譯器有多強大多智能?
寫的人思維都要轉換幾次,編譯器轉著圈嵌著套翻著番兒地編譯代碼的代碼也肯定是無比蛋疼的,你說它有多強大多智能?
一個代碼創造另外一個代碼,自己能按照相似的規則生成自己,是不是聽上去已經有人工智慧的發展趨勢了?
上帝說,要有光,於是有了光。
老子曰,一生二,二生三,三生萬物。
信c++,得永生!
===
FBI WARNING:模板元編程雖然很強大,但也有不少缺點,尤其對於大型項目,為了你以及身邊同事的身心健康,請務必適度且謹慎的使用。勿亂入坑,回頭是岸。
【以下解答】
c++11的auto自動類型推斷算么....
【以下解答】
智能到開不同級別的優化,程序行為會不同 2333
【以下解答】
這個取決於你的水平

❷ C++中常量賦值是如何規定的

1、值替代
c語言中預處理器用值代替名字:

#define BUFSIZE 100

這種方式在C++中依然適用,同時

C++用const把值代替帶進編譯器領域:
const bufsize = 100 ;或 const int bufsize = 100 ;
同時還可以執行常量折疊:
char buf[bufsize] ;
1.1 頭文件里的const
與使用#define一樣,使用const必須把const定義放在頭文件里。這樣,通過包含頭文件,可把const定義單獨放在一個地方,並把她分配給一個編譯單元。const默認為內部連接,即僅在const被定義過的文件里才是可見的,而在連接時不能被其他編譯單元看到。
比如說在Test.h中定義了,

const int nTestConst = 1000;

在A.cpp中include"Test.h"
同時在B.cpp中include"Test.h"
不會出現,當沒有定義為const時,因變數定義出現兩次而出錯的情形.
當定義一個const常量時,必須賦一個值給它,除非用extern作了清楚的說明:

extern const bufsize ;

雖然上面的extern強制進行了存儲空間分配,但C++編譯器並不為const分配存儲空間,相反它把這個定義保存在它的符號表裡。當const被使用時,它在編譯時會進行常量折疊。

1.2 const的安全性
如果想要一個值保持不變,就應該使它成為一個常量(const)。
1.3 集合
const可以用於集合,但必須分配內存,意味著「不能改變的一塊存儲」。但其值在編譯時不能被使用。


const int i [] = {1,2,3,4};
// float f [ i [3] ]; // Illegal

2,指針
當使用帶有指針的const時,有兩種選擇:1、或者const修飾指針正指向的對象,2、const修飾存儲在指針本身的地址。
2.1 指向const的指針
使用指針定義的技巧,正如任何復雜的定義一樣,是在標識符的開始處讀它並從里到外讀。如果我們要使正指向的元素不發生改變,得寫:

const int * x;

從標識符開始:「x 是一個指針,指向一個const int。」
把const從一邊移到另一邊,結果一樣。
int const * x;
2.2 cosnt指針
是指針本身成為一個const指針,必須把const標明的部分放在*的右邊,如:

int d = 1;
int * const x = &d;

指針本身是const指針,編譯器要求給它一個初始化值,這個值在指針壽命期間不變。然而要改變它所指向的值是可以的,可以寫*x = 2。
這些可以總結成這樣一句話:
以*為分界點,
當const在*的左邊時,實際物體值不變
當const在*的右邊時,指針不變,
即,左物右指
這樣來記比較方便!!

❸ keil編譯器前面的這些 加減符號如何修改

選中你想要能夠收縮的代碼,右鍵-->outlining --> collapse Selection ;就可以將自己想要收縮的代碼行收縮咯,collapse 為折疊的意思,outlining裡面還有幾個選項,可以自己試試功能。 我也是網上查找無果,還是花了點時間才發現的哦,望採納!

javashort怎麼-1

註:如未特別說明,Java語言規范 jls 均基於JDK8,使用環境是 eclipse4.5 + win10 + JDK 8
本篇的知識點,主要是涉及到 Java 中一些比較答橡雹常見的默認窄化處理(Java編譯器自動添加的),這里將從一個問題開始,據說這也是一道常見的筆試題/面試題:

為什麼 short i = 1; i += 1; 可以正確編譯運行而 short i = 1; i = i + 1; 會出現編譯錯誤?

其他說法:都放在一起編譯會出現有什麼結果,哪一行報錯?為什麼?

筆者註:其實這其中會涉及到一些編譯優化和底層的知識,限於知識面,本篇不涉及,如有需要,可自行搜索。

本文的目錄結構如下:

1、結論

關於開篇提出的問題,這里先直接給出結論:

Java語言規范規定基礎數據類型運算默認使用32位精度的int類型

只要是對基本類型做窄化處理的,例如 long -> int -> short -> char,都需要做強制轉換,有些是Java編譯器默認添加的,有的則是代碼中顯式做強制轉換的。

short i = 1; i += 1;可以正確編譯運行是因為Java編譯器自己添加了強制窄化處理,即對於任何的T a; X b; a += b;等價於T a; X b; a = (T) (a + b);Java編譯器會默認做這個顯式強制轉換(盡管有時候會出現精度問題,例如 b 是 float 、 double 類型,強烈建議不要有這樣的操作)。前面的i += 1其實就等價於i = (int) (i + 1),即便將數字1換成是double類型的1.0D也是如此。

short i = 1; i = i + 1;編譯不通過的原因就很明顯了:無論是代碼中,還是Java編譯器,都沒有做強制轉換,int 類型直接賦給 short ,因此編譯出錯。

對於常量(數字常量、常量表達式、final常量等),Java編譯器同樣也可以做默認的強制類型轉換,只要常量在對應清帆的數據范圍內即可。

2、詳如殲解

接下來講詳細分析為什麼 short i = 1; i += 1; 可以正確編譯而 short i = 1; i = i + 1; 則會編譯失敗。先列一下搜出來的一些令人眼前一亮(or 困惑)的代碼

public static voidmain(String[] args) {//注:short ∈ [-32768, 32767]

{/** 1、對於 +=, -=, *=, /=, Java編譯器默認會添加強制類型轉換,

* 即 T a; X b; a += b; 等價於 T a; X b; a = (T) (a + b);*/

//0是int類型的常量,且在short范圍內,被Java編譯器默認強制轉換的

short i = 0;

i+= 1; //等價於 i = (short) (i + 1);

System.out.println("[xin01] i=" + i); //輸出結果: 1

i = (short) (i + 1);

System.out.println("[xin02] i=" + i); //輸出結果: 2

/** 下面這2行都會有編譯報錯提示:

* Exception in thread "main" java.lang.Error: Unresolved compilation problem:

* Type mismatch: cannot convert from int to short

* [注]錯誤: 不兼容的類型: 從int轉換到short可能會有損失

* Eclipse 也會有提示: Type mismatch: cannot convert from int to short*/

//i = i + 1;//i = 32768;

i= 0;

i+= 32768; //等價於 i = (short) (i + 32768); 下同

System.out.println("[xin03] i=" + i); //輸出結果: -32768

i += -32768;

System.out.println("[xin04] i=" + i); //輸出結果: 0

i= 0;long j = 32768;

i+=j;

System.out.println("[xin05] i=" + i); //輸出結果: -32768

i= 0;float f = 1.23F;

i+=f;

System.out.println("[xin06] i=" + i); //(小數位截斷)輸出結果: 1

i= 0;double d = 4.56D;

i+=d;

System.out.println("[xin07] i=" + i); //(小數位截斷)輸出結果: 4

i= 10;

i*= 3.14D;

System.out.println("[xin08] i=" + i); //輸出結果: 31

i= 100;

i/= 2.5D;

System.out.println("[xin09] i=" + i); //輸出結果: 40

}

{/** 2、常量表達式和編譯器優化: 常量折疊*/

//2 * 16383 = 32766//(-2) * 16384 = -32768//都在 short 范圍內,常量表達式在編譯優化後直接用對應的常量結果,然後編譯器做強制轉換

short i = 2 * 16383; //等價於 short i = (short) (2 * 16383);

short j = (-2) * 16384;//2 * 16384 = 32768,超過 short 范圍,編譯器不會做轉換//Type mismatch: cannot convert from int to short//short k = 2 * 16384;//常量表達式在編譯優化後直接用對應的常量結果,然後編譯器做強制轉換

short cThirty = 3 * 10;short three = 3;short ten = 10;//Type mismatch: cannot convert from int to short//short thirty = three * ten;

final short fTthree = 3;final short fTen = 10;//常量表達式在編譯優化後直接用對應的常量結果,然後編譯器做強制轉換

short fThirty = fTthree *fTen;final short a = 16384;final short b = 16383;//常量表達式在編譯優化後直接用對應的常量結果,然後編譯器做強制轉換

short c = a +b;

}

}

接下來根據代碼羅列的兩部分分別進行說明:

2.1、對於 +=, -=, *=, /=, Java編譯器默認會添加強制類型轉換,即 T a; X b; a += b; 等價於 T a; X b; a = (T) (a + b);

A compound assignment expression of the formE1 op= E2is equivalent toE1 = (T) ((E1) op (E2)), whereTis the type ofE1, except thatE1is evaluated only once.

For example, the following code is correct:

short x = 3;

x+= 4.6;

and results in x having the value 7 because it is equivalent to:

short x = 3;

x= (short)(x + 4.6);

筆者註:

實際上,直接加上強制類型轉換的寫法,也是大家都熟悉且理解起來最清晰的方式,可以避免可能潛在的類型不匹配時出現的精度損失問題,使用的時候需要注意。當然,筆者認為這些方式都沒有好壞之分,正確地使用即可。

Java從語言規范層面對此做了限制。有興趣的還可以通過 class文件和 javap -c 反匯編對所使用的位元組碼作進一步的研究。

知道了Java語言相關的規范約定,我們就可以看出,與之對應的是以下這種出現編譯錯誤的寫法(報錯提示:Type mismatch: cannot convert from int to short):

short i = 1;//i + 1 是 int 類型,需要強制向下類型轉換

i = i + 1;

2.2、常量表達式和編譯器優化: 常量折疊

需要注意的是,前面的示例short x = 3;中的3其實默認是 int 類型,但是卻可以賦值給short類型的x。這里涉及到到的其實是 常量表達式。

In addition, if the expression is a constant expression (

A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:

Byte and the value of the constant expression is representable in the type byte.

Short and the value of the constant expression is representable in the type short.

Character and the value of the constant expression is representable in the type char.

對於常量表達式,其結果是可以自動做窄化處理的,只要是在對應的數據類型範圍內,Java編譯器就進行做默認強制類型轉換。

Some expressions have a value that can be determined at compile time. These are constant expressions (

true(short)(1*2*3*4*5*6)

Integer.MAX_VALUE/ 2

2.0 *Math.PI"The integer " + Long.MAX_VALUE + " is mighty big."

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (

通過常量表達式賦值的final變數都是常量,這種也是編譯期可以確認最終值,會通過編譯優化直接賦予最終值,而且可以直接依靠編譯器做窄化處理。

對於這一塊,其實對應的是一個比較基礎的編譯器優化:常量折疊(Constant Folding),有興趣的可以自行搜索。stackoverflow 上由相關的討論,參考[9]、[10]、[11]

筆者註:

盡管常量表達式最終都被編譯器優化為直接值,但是為了清晰,提高可讀性、可維護性,代碼中沒必要對常量直接換算,例如一天 24 * 60 * 60 秒,其實可以分別用可讀性更強的final常量來表示。

Bloch大神的 Java Puzzlers 中也有相關的一些說明,有興趣的可以去看看

❺ C語言編寫好代碼後,怎麼編譯,最後生成可執行文件

材料/工具:vc6.0

1、打開c語言編輯工具,在工具中寫入程序的源代碼。

熱點內容
蘋果6怎麼設置短密碼 發布:2025-03-19 04:44:41 瀏覽:17
三人樂隊怎麼配置 發布:2025-03-19 04:34:42 瀏覽:914
趣編程入口 發布:2025-03-19 04:25:09 瀏覽:939
a的存儲形式 發布:2025-03-19 04:24:00 瀏覽:789
android鍵盤修改 發布:2025-03-19 04:21:45 瀏覽:165
記錄體溫源碼 發布:2025-03-19 04:14:06 瀏覽:895
安卓電池充電次數怎麼查看 發布:2025-03-19 04:08:44 瀏覽:318
問解壓 發布:2025-03-19 03:29:44 瀏覽:811
原神手機號如何修改賬號密碼 發布:2025-03-19 03:29:22 瀏覽:188
汽車配置哪些最省錢 發布:2025-03-19 03:10:16 瀏覽:518