是否有任何 C99 编译器的默认设置为 -1>>1 != -1?
Are there any C99 compilers where with default settings -1>>1 != -1?
许多人在讨论右移运算符时经常指出,C标准明确指出,负数右移的效果是实现定义的。我可以理解这句话的历史基础,因为C编译器已经被用来为各种不使用二补运算的平台生成代码。然而,据我所知,所有新产品的开发都围绕着处理器展开,这些处理器除了二补之外,对任何一种整数运算都没有固有的支持。
如果代码希望执行二次幂的落地有符号整数除法,并且它只在当前或未来的体系结构中运行,那么任何未来的编译器都会将右移运算符解释为做其他事情,这是否存在现实的危险?如果有现实的可能性,有没有什么好的方法可以在不影响可读性、性能或两者的情况下提供它?是否有任何其他依赖关系可以证明直接假设操作员的行为是合理的(例如,代码在不支持函数X的实现上是无用的,如果不使用符号扩展右移,则实现不太可能支持X)?
注意:我在C99和C11标签下询问,因为我希望更新的语言功能将是其中之一,如果支持的话,这将表明平台可能会使用算术上等效于地板除法的右移,并且我有兴趣了解任何以任何其他方式实现右移的C99或C11编译器。
这只是造成这种情况的众多原因之一,但请考虑信号处理情况:
1111 0001 >> 1
0000 1111 >> 1
在你提到的右移算术(SRA)的形式中,你会得到以下内容:
1111 0001 >> 1 = 1111 1000
OR
-15 >> 1 = -8
0000 1111 >> 1 = 0000 0111
OR
15 >> 1 = 7
那么问题出在哪里呢?考虑振幅为15"单位"的数字信号。将该信号除以2应产生等效行为,而不考虑符号。然而,对于如上所述的SRA,15的正信号将产生具有7振幅的信号,而15的负信号将产生带有8振幅的信号。这种不均匀性导致输出中的DC偏置。出于这个原因,一些DSP处理器选择实现"四舍五入到0"的右移算法,或者其他方法。因为C99标准的措辞是这样的,所以这些处理器仍然可以兼容。
在这些处理器上,-1 >> 1 == 0
相关Wiki
从理论上讲,如今编译器实现中存在一些微妙之处,可能会滥用所谓的"未定义行为",超出后端cpu对寄存器(或"文件"或内存位置或其他位置)上的实际整数的处理:
-
交叉编译器是常见的东西:编译器在执行简单计算时可能会滥用依赖于实现的规范。考虑目标体系结构以一种方式实现这一点而以另一种方式托管的情况。在您的特定示例中,编译时常数可能最终为1,即使目标体系结构中的任何程序集输出都会为0(我想不出没有这样的体系结构)。反之亦然。编译器实现者不需要关心其他方面(除了用户群抱怨)。
-
考虑一下CLANG和其他生成中间抽象代码的编译器。没有什么可以阻止类型机制在某些代码路径上的中间时间优化某些操作直到最后一位(即,当它可以将代码减少为常量时,会想到循环折叠),同时让程序集后端在其他路径的运行时解决此问题。换句话说,您可以看到混合行为。在这种抽象中,实现者没有义务遵守C语言所期望的任何标准之外的任何标准。想想这样的情况,所有整数运算都是由任意精度的算术库完成的,而不是直接映射到主机cpu整数。无论出于何种原因,实现都可能决定这是未定义的,并返回0。它可以对任何有符号的算术未定义行为执行此操作,并且在ISO C标准中有很多,特别是包装之类的。
-
考虑一下(理论上)的情况,编译器劫持了一个子操作,而不是发出完整的指令来执行低级操作。这方面的一个例子是带有桶形移位器的ARM:显式指令(即add或其他任何指令)可以具有范围和语义,但子操作的操作限制可能略有不同。编译器可以在行为可能不同的情况下最大限度地利用这一点,例如,一种情况可以设置结果标志,而另一种情况不能。我想不出具体的例子,但有些奇怪的指令可能只能处理"其他正常行为"的子集,编译器可能会认为这是一个很好的优化,因为未定义的行为实际上意味着未定义:-)
除了你在运行时会有奇怪行为的奇怪架构之外,我能想到的一些原因就是为什么你不能假设任何超出未定义行为的东西。
尽管如此,我们还必须考虑:
- 你要求C99编译器。大多数奇怪的体系结构(即嵌入式目标)都没有C99编译器
- 大多数"大规模"编译器实现者处理非常大的用户代码库,并且通常通过过度优化细微之处来面对支持噩梦。所以他们没有。或者他们像其他玩家那样做
- 在有符号整数"未定义行为"的特殊情况下,通常互补的无符号运算是一个已定义的运算,即我看到过将有符号转换为无符号的代码只是为了执行运算,然后再将结果转换回
我想我能给出的最好的直接答案是"你可能认为这一切都无关紧要,但也许你不应该"。
- EASTL矢量<向量<int>>连续的
- 将长度可变的 C99 静态 3D 数组传递给函数
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- C 字符串比较“祝您好运”&gt;“再见”
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C99 中的_Complex类型在 C++ 中的行为是否类似于 std::complex<>?
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- C 操作员&gt;&gt;与突变器过载
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 是否需要使用 - &gt;运算符在C 中调用成员函数时
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- 也是C 中C99的所有功能
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- 错误c++visual studio c2227左侧'->;Init';必须指向类/结构/联合/泛型类型
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- ``这个''不能用this-&gt;指针变量
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在