出于纯粹的兴趣,我一直在学习C和计算机科学主题,这让我对编译器产生了兴趣.我读过的所有东西都告诉我,混叠会导致汇编输出变慢,这需要在每次迭代时重新加载值.

在使用标志-fno-alias的英特尔C/C++编译器中,我已经能够在一些基准测试中略微提高.GCC和Lang/LLVM没有同等的旗帜.我猜有-fargument-noalias-fargument-noalias-global禁用了函数参数的别名-please correct me if I'm wrong-但我没有注意到它在运行时甚至编译时性能上有什么不同.

这份声明是否

别名会阻止编译器执行某些优化,从而影响性能.

始终保持正确,编译器别名的好处是什么?为什么它是现代编译器的一个功能,除了英特尔编译器外,不能使用标志轻松关闭它?没有别名的编译会导致代码不符合ABI标准吗?

推荐答案

编译器不执行别名.您的程序可能会执行别名.

编译器要么允许您执行别名,要么假定您没有执行别名,然后编写如果您执行了别名则不起作用的机器码.

例如,您可以编写如下代码:

void f(int *x, int *y, int *z) {
    *y += *x;
    *z += *x;
}

该函数只是将*x*y*z相加,对吗?所以汇编代码应该是这样的,对吗?(我用伪C编写汇编代码)

eax = argument x
ebx = argument y
ecx = *eax
*ebx += ecx
ebx = argument z
*ebx += ecx

103如果yx指向同一位置,则此汇编代码的工作方式与C代码不同,因为它使用old *x.要正确运行,它必须是这样的:

eax = argument x
ebx = argument y
ecx = *eax
*ebx += ecx
ebx = argument z
ecx = *eax // extra instruction
*ebx += ecx

这是另一条指令,只有在x==y的情况下才有用,但编译器必须把它放在那里,以防万一.Aliasing表示*x*y是同一变量的不同名称.如果编译器假设xy不能是同一个指针(即没有别名),那么它可以跳过这条指令,因此指令更少,程序运行得更快.

您可以使用单词restrict来告诉编译器它们没有别名,如下所示:

void f(int *restrict x, int *restrict y, int *restrict z) {
    *y += *x;
    *z += *x;
}

-fno-alias告诉英特尔编译器别名不能在任何地方发生.这可能会产生错误somewhere,因为参数有时会产生别名--尽管它可能在没有别名的小程序上工作得很好.restrict更仔细地针对您知道不会有别名的特定参数.

C++相关问答推荐

C中的整字母后缀i是什么

问关于C中的指针和数组

带双指针的2D数组

字符串令牌化xpath表达式

将 typewriter LF打印到Windows终端,而不是隐含的CR+LF

核心转储文件中出现奇怪的大小变化

C中的指针增量和减量(*--*++p)

向上强制转换C中的数值类型总是可逆的吗?

如何有效地编写代码来判断两个元素数量相同的数组即使在不同的位置也具有相同的元素?

如何在STM8项目中导入STM8S/A标准外设库(ST VisualDeveloper)?

-Wnonnull-Compare警告不是具有误导性吗?

链表删除 node 错误

int * 指向int的哪个字节?

c程序,让用户输入两类数字,并给出输出用户输入多少个数字

C编译和运行

Tcl_GetDoubleFromObj在列表的迭代中是一个缺点

函数的typedef是标准 C 语法吗?它与函数指针的typedef有何不同?

为什么 Linux 共享库 .so 在内存中可能比在磁盘上大?

是什么阻止编译器优化手写的 memcmp()?

为什么 C 字符串并不总是等同于字符数组?