zoukankan      html  css  js  c++  java
  • 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
    ", 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派生类的类型
  • 相关阅读:
    sshkey批量分发,管理方案
    sersync 配合rsync实时同步备份
    全网实时热备inotify+rsync
    rsync定时同步配置
    全网NFS存储架构详解与分析
    linux新装系统初始化
    Cannot create a secure XMLInputFactory --CXF调用出错
    POJ 2187 /// 凸包入门 旋转卡壳
    POJ 1127 /// 判断线段与线段是否相交
    POJ 2398 map /// 判断点与直线的位置关系
  • 原文地址:https://www.cnblogs.com/ZisZ/p/9105383.html
Copyright © 2011-2022 走看看