C/C++ strict-aliasing

來源:互聯網
上載者:User

標籤:結構體   char*   tutorials   聯合   fill   html   blog   4.4   gap   

最近發現了一個奇怪的編譯參數-fno-strict-aliasing,好奇之下做了一點研究;

 

重點參考Understanding C/C++ Strict Aliasing;

所謂的aliasing就是多個變數指向同一塊記憶體,變數之間互為別名;

strict-aliasing是一種編譯器希望開發人員遵守的規則:雖然C/C++變數可以隨便賦值(強制類型轉換),但也請你們收斂一點,別太天馬行空了;

如果開發人員按照這個規則寫代碼了,編譯器就可以做更好的代碼最佳化,比如這個例子:

void foo(double *dblptr){    anint = 1;    *dblptr = 0;    bar(anint);}

如果開發人員能夠注意不要把int*轉成double*,bar(anint)可以直接最佳化成bar(1);

但沒有任何約束不允許這樣做,因而編譯器不敢做這樣的最佳化,只能在bar(anint)將anint傳入bar之前加一條彙編指令再讀一下anint的值;

如果開發人員確定自己的代碼遵守這樣的規則了,可以在編譯時間加一個最佳化參數-fstrict-aliasing,這個參數在gcc的-O2、-O3、-Os最佳化層級下都是預設開啟的。

 

然後我對Understanding C/C++ Strict Aliasing文中的兩個主要例子做了一下測試:

例子一:

#include <stdio.h>int anint;void bar(int a){    printf("%d\n", a);}void foo(double *dblptr){    anint = 1;    *dblptr = 0;    bar(anint);}int main(){    foo((double*)&anint);    return 0;}
編譯器版本 編譯參數 結果
gcc 4.4.7 g++ 0
  g++ -O3 1
  g++ -O3 -fno-strict-aliasing 0
gcc 4.8.5 g++ 0
  g++ -O3 1
  g++ -O3 -fno-strict-aliasing 0
gcc 7.3.0 g++ 0
  g++ -O3 1
  g++ -O3 -fno-strict-aliasing 0

 可以看到,這個case被gcc編譯器最佳化壞了,可以用-fno-strict-aliasing規避;

 

例子二:

#include <iostream>#include <iomanip>using namespace std;typedef unsigned int uint32_t;typedef unsigned short uint16_t;uint32_t swaphalves(uint32_t a) {  uint32_t acopy = a;  uint16_t *ptr = (uint16_t*)&acopy;// can‘t use static_cast<>, not legal.                                    // you should be warned by that.  uint16_t tmp = ptr[0];  ptr[0] = ptr[1];  ptr[1] = tmp;  return acopy;}int main() {  uint32_t a;  a = 32;  cout << hex << setfill(‘0‘) << setw(8) << a << endl;  a = swaphalves(a);  cout << setw(8) << a << endl;}
編譯器版本 編譯參數 結果
gcc 4.4.7 g++ 00000020
00200000
  g++ -O3 00000020
00000020
gcc 4.8.5 g++ 00000020
00200000
  g++ -O3 00000020
00200000
gcc 7.3.0 g++ 00000020
00200000
  g++ -O3 00000020
00200000

發現這個case有點意思,只在4.4版本的編譯器上會出現問題,高版本編譯器上已經修正了。

沒有精力再深入研究,就到此為止。

 

最後再貼上strict aliasing的規則說明,下面這篇文章給出了較好的中文翻譯,而且作者顯然比我研究的更深入,我就直接抄過來了:

6720141

  • 相容類型(指相同類型?)或差別僅在於signed、unsigned、const、volatile的類型(比如 const unsigned long *和 long*)
  • 彙總類型(struct或class)或等位型別(union)可以alias它們所包含的類型(比如 int 和 包含有int的結構體(包括間接包含))
  • 字元類型(char *、signed char*、unsinged char*)可以 alias 任何類型的指標
  • [C++] 基類的類型(可能帶有const、volatile等cv修飾)可以alias衍生類別的類型

 

C/C++ strict-aliasing

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.