C/C++ strict-aliasing
最近发现了一个奇怪的编译参数-fno-strict-aliasing,好奇之下做了一点研究;
重点参考Understanding C/C++ Strict Aliasing;
所谓的aliasing就是多个变量指向同一块内存,变量之间互为别名;
strict-aliasing是一种编译器希望开发者遵守的规则:虽然C/C++变量可以随便赋值(强制类型转换),但也请你们收敛一点,别太天马行空了;
如果开发者按照这个规则写代码了,编译器就可以做更好的代码优化,比如这个例子:
void foo(double *dblptr)
{
anint = ;
*dblptr = ;
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 = ;
*dblptr = ;
bar(anint);
} int main()
{
foo((double*)&anint);
return ;
}
编译器版本 | 编译参数 | 结果 |
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[];
ptr[] = ptr[];
ptr[] = tmp;
return acopy;
} int main() {
uint32_t a;
a = ;
cout << hex << setfill('') << setw() << a << endl;
a = swaphalves(a);
cout << setw() << a << endl;
}
编译器版本 | 编译参数 | 结果 |
gcc 4.4.7 | g++ | 00000020 00200000 |
g++ -O3 | ||
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派生类的类型
C/C++ strict-aliasing的更多相关文章
- [翻译]类型双关不好玩:C中使用指针重新解释是坏的
原文地址 Type punning isn't funny: Using pointers to recast in C is bad. C语言中一个重新解释(reinterpret)数据类型的技巧有 ...
- 一个快速double转int的方法(利用magic number)
代码: int i = *reinterpret_cast<int*>(&(d += 6755399441055744.0)); 知识点: 1.reinterpret_cast&l ...
- Python 代码优化常见技巧
代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化.扩展以及文档相关的事情通常需要消耗 80% 的工作量.优化通常包含两方 ...
- [转] Python 代码性能优化技巧
选择了脚本语言就要忍受其速度,这句话在某种程度上说明了 python 作为脚本的一个不足之处,那就是执行效率和性能不够理想,特别是在 performance 较差的机器上,因此有必要进行一定的代码优化 ...
- Python 代码性能优化技巧
选择了脚本语言就要忍受其速度,这句话在某种程度上说明了 python 作为脚本的一个不足之处,那就是执行效率和性能不够理想,特别是在 performance 较差的机器上,因此有必要进行一定的代码优化 ...
- fstrict-aliasing
承如“optimization blocks”文中所述,由于相同的指针可能指向相关的内存区,因此编译器将不做过分的优化…… 特意搜了下编译器在不同的优化等级下都有哪些默认优化,因此有了此记录(比较长, ...
- 解决部分在Debug模式下程序没问题但是Release模式下出现问题的方法
编译策略介绍 关于优化级别:GCC_OPTIMIZATION_LEVEL 描述如下 None: Do not optimize. [-O0]With this setting, the compil ...
- Linux System Programming 学习笔记(九) 内存管理
1. 进程地址空间 Linux中,进程并不是直接操作物理内存地址,而是每个进程关联一个虚拟地址空间 内存页是memory management unit (MMU) 可以管理的最小地址单元 机器的体系 ...
- Linux下编译安装源码包软件 configure ,make, make install, make test/check, make clean
http://www.360doc7.net/wxarticlenew/541275971.html 一.什么是源码包软件? 顾名思义,源码包就是源代码的可见的软件包,基于Linux和BSD系统的软件 ...
随机推荐
- 转:SQL Server 动态行转列
http://www.cnblogs.com/gaizai/p/3753296.html http://www.cnblogs.com/maanshancss/archive/2013/03/13/2 ...
- python目录遍历文件名称替换
# -*- coding:utf-8 -*- import os import os.path import shutil import chardet import codecs mysql_fil ...
- Python实现代码统计工具——终极加速篇
Python实现代码统计工具--终极加速篇 声明 本文对于先前系列文章中实现的C/Python代码统计工具(CPLineCounter),通过C扩展接口重写核心算法加以优化,并与网上常见的统计工具做对 ...
- MYSQL 内存模型
- react build后直接从浏览器打开
存在两个问题 一,资源文件路径 config/paths.js 这里原来的.pathname:'/', 改成.pathname:'./' function getServedPath(appPacka ...
- HTML5在手机端实现视频全屏展示
最近做项目,遇到一个问题,在手机上要实现视频的全屏播放功能.测试了很久,终于找到解决办法. 第一种:将视频放大来控制. 视频在播放的时候,全屏是根据高度来的,如果设置视频 video 标签的宽度是 1 ...
- php跨域发送请求原理以及同步异步问题
<script async type="text/javascript" src="http://lisi.com/data.php?flag=1"> ...
- centos7 与 archlinux用户 安装 python3模块 pytaglib
对于 centos7用户: yum group install "Development Tools" yum install taglib-devel yum install p ...
- 剑指offer——python【第43题】左旋转字符串
题目描述 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=”abc ...
- Oracle课程档案,第八天
存储管理 查询块的大小:show parameter db_block_size database:数据库 tablespace:表空间 datafile:数据文件 segments:段 extent ...