首页 > 其他分享 >C语言之Strict Aliasing(严格别名)

C语言之Strict Aliasing(严格别名)

时间:2024-09-11 20:21:40浏览次数:3  
标签:int Aliasing aliasing 别名 C语言 Strict 编译器 内存 type

C语言之Strict Aliasing(严格别名)

alias(别名)

C语言的左值(lvalue)和右值(rvalue)的含义

以赋值符号 = 为界,= 左边的就是左值,= 右边就是右值。

比如:(1) int b = 3;(2) int a = b;第(2)行代码,a为左值,b为右值。

可以将 L-value 的 L, 理解成 Location,表示定位、地址。将 R-value 的 R 理解成 Read,表示读取数据,数据放在内存中,内存有两个基本的属性:内存地址和里面的数据。变量名编译之后,会映射成内存地址。看看a = b的含义。其实就是 将 b地址内存里面的数据,放到a地址内存中。

在 C 中,当多个左值 lvalue 指向同一个内存区域时,就会出现别名(alias),一个内存区域可以有很多别名。

strict aliasing(严格别名)

编译时,编译器会在不影响程序功能的情况下进行优化,比如指令重排等,所以执行的程序可能完全不是我们所写的程序,只是功能一样。当别名不受限制时,比如int指针也可以指向保存float的内存,每块内存的内容可能会被任何先前的内存存储所改变。导致编译器在优化时考虑每个指针都可能指向同一个内存,不敢轻易优化深怕影响程序功能,严重限制优化空间。比如

void add(long *a, int *b)
{
    *a += *b;
    *a += *b;
}
void add(long *a, int *b)
{
    *a += 2 * *b;
}

如果a和b不会指向同一块内存,那么两个函数功能一样,都是a=a+2b,但是如果a和b有可能指向同一块内存那么两个函数功能就不一样了,第一个变成a=4a,第二个还是a=a+2b。

所以为了更加方便编译优化引入严格别名规则和相关的编译选项

通过 -fstrict-aliasing选项(O2以上默认开启)让编译器认为代码中都是符合严格别名规则的,可以大胆的去优化, -fno-strict-aliasing反之,同时可以可以通过-Wstrict-aliasing选项告警不符合严格别名规则帮助开发者排查,对应的-Wno-strict-aliasing屏蔽告警

当开始-fstrict-aliasing编译选项时,如果代码违反严格别名规则,那么将是一种不可控的行为(undefined behavior),可能会编译出各种未知的问题。

strict aliasing rule(严格别名规则)

在 C11 标准(N1570)中的定义如下

  • a type compatible with the effective type of the object(相互兼容类型)
int a = 1;
int *b = &a;
  • a qualified version of a type compatible with the effective type of the object(相互兼容类型的限定版本)
int a = 1;
const int *b = &a;
  • a type that is the signed or unsigned type corresponding to the effective type of the object(对应的有无符号类型)
int a = 1;
unsigned int *b = (unsigned int *)&a;
  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object(对应的有无符号类型的限定版本)
int a = 1;
const unsigned int *b = (const unsigned int *)&a;
  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union)(聚合或union类型,其成员中包括上述类型之一)
struct {
    int a;
} aa = {0};
int *b = &aa;
  • a character type(字符类型)
int x = 65;
char *p = (char *)&x;//万能的字符指针

restrict 关键字

有时即使两个变量可能符合strict aliasing rule(严格别名规则),但我们保证他们不会指向同一片内存空间,可以通过restrict 关键字告诉编译器,变量独占内存块,不会有其他变量指向改内存块,以让编译器放手去优化。如下

void add(int *a, int *b)
{
    *a += *b;
    *a += *b;
}

如果不加restrict关键字,那么a和b可能指向同一块地址,所以编译器不会去优化,只会老实按顺序执行,但是如果我们通过关键字restrict告诉编译器,a和b不会指向同一块内存,那么编译可能会将其优化成如下

void add(int * restrict a, int * restrict b)
{
    *a += *b;
    *a += *b;
}
void add(int *a, int *b)
{
    *a += 2 * *b;
}

标签:int,Aliasing,aliasing,别名,C语言,Strict,编译器,内存,type
From: https://blog.csdn.net/dengdui/article/details/142028341

相关文章

  • 【C语言基础】指针
    1指针与地址,指针变量地址就是内存区中对每个字节的编号。如整型变量a、b、c,整型变量需要4个字节,分配的地址分别为1000、1004、1008。可以通过访问变量的地址来找到所需的变量,我们称变量的地址为变量的“指针”。上例中的1000、1004、1008分别为变量a、b、c的指针。指针变量......
  • C语言中 '=='的优先级高于 '&' '|' '&&' '||'
    之前一直以为 '=='的优先级低于  '&''|',但是这是错误的, '=='的优先级高于'&''|''&&''||',同时使用时,记得加括号修改优先级。 第一优先级:[]       ()      .      ->   方括号,圆括号,对象,......
  • 22级五年制C语言入门教程-(5)格式化输入输出
    1.输入和输出在程序的使用中,我们经常可以看的这么一个场景:用户需要输入数据,经过程序运算,得到结果后输出。在C语言中,输入数据和输出数据都是由库函数完成的,通过语句来输入/输出。2.格式化输出—printf()函数C语言程序运算的结果在内存中,我们需要将其输出到指定设备中,我们才可以......
  • 22级五年制C语言入门教程-(6)运算符
    1.运算符概述运算符是一种编译器执行特定的数学或逻辑操作的符号。C语言提供了以下类型的运算符:算术运算符关系运算符逻辑运算符位运算符赋值运算符条件运算符其他运算符2.算术运算符算术运算符分为单目运算符和双目运算符,单目运算符表示只需要一个操作数,双目运算符需......
  • 启程,新手学习c语言的第一天
     今天是我开始学习c语言的第一天,通过网上查询资料得知写博客对程序员的成长有很大帮助,于是开始在学习的同时开始写一写博客。 我明白自己是一个什么都不知道的新手,一开始也写不出什么有实质性内容的东西。所以目前的播客主要是记录自己的学习经历,通过这一方式来对学习过的......
  • C语言的数据在内存中的存储
    在之前的二进制及其相关操作符与结构体内存对齐两篇文章中,我们已经对二进制数,原码反码补码进行了浅层的了解,并且也知道了高低地址以及高低字节的区别,那么既然知道了这些基础知识,就让我们借助这一层台阶,继续往更高的地方(数据在内存中的存储)大迈步吧~一、二进制数日常生活中......
  • 22级五年制C语言入门教程-(2)基本程序结构
    1.简单的C语言程序结构要建造房屋,首先需要打地基、搬砖搭建框架(这大概就是为什么叫搬砖的原因)。学习计算机语言的时候也一样,应该从基本的结构开始学起。下面,我们看一段简单的源代码,这段代码希望大家动手对着敲一遍,自己动手完完全全敲一次。我想对于刚学编程的人,即使对着敲,也是极......
  • 22级五年制C语言入门教程-(3)基本数据类型
    1.数据类型在C语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统。C语言数据类型可以分为四种:1.基本类型:它们是算术类型,包括两种类型:整数类型和浮点类型。2.枚举类型:它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量。3.void类型:类型......
  • 22级五年制C语言入门教程-(4)常量和变量
    1.常量和变量的概念程序执行过程中其值不能发生改变的量叫做常量,其值能发生改变的量叫做变量。常量可以直接使用,而变量则必须先定义后才能使用,否则编译器会报错。2.常量和变量的命名规范在介绍常量和变量的命名规范之前,我们先了解一下什么是标识符和关键字。2.1标识符标识符......
  • C语言入门教程-(1)简介及搭建环境
    转载知乎https://zhuanlan.zhihu.com/p/52111695https://zhuanlan.zhihu.com/p/52259238https://zhuanlan.zhihu.com/p/52800353https://zhuanlan.zhihu.com/p/53568364https://zhuanlan.zhihu.com/p/54100371https://zhuanlan.zhihu.com/p/54278100 1.谁适合阅读本教程......