C/C++ strict-aliasing
最近發現了一個奇怪的編譯參數-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的規則說明,下面這篇文章給出了較好的中文翻譯,而且作者顯然比我研究的更深入,我就直接抄過來了:
https://blog.csdn.net/dbzhang800/article/details/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派生類的類型
?
轉載于:https://www.cnblogs.com/ZisZ/p/9105383.html
總結
以上是生活随笔為你收集整理的C/C++ strict-aliasing的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPF整理-为User Control添
- 下一篇: c++基本语法