Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否有任何C99编译器的默认设置为-1>&燃气轮机;1 != -1._C++_C_C99_Bit Shift_C11 - Fatal编程技术网

C++ 是否有任何C99编译器的默认设置为-1>&燃气轮机;1 != -1.

C++ 是否有任何C99编译器的默认设置为-1>&燃气轮机;1 != -1.,c++,c,c99,bit-shift,c11,C++,C,C99,Bit Shift,C11,许多人在讨论右移运算符时经常指出,C标准明确规定,负数右移的效果由实现定义。我可以理解这种说法的历史依据,因为C编译器已经被用于为各种不使用二补运算的平台生成代码。然而,据我所知,所有的新产品开发都是围绕着处理器展开的,这些处理器除了2的补码外,对任何类型的整数运算都没有内在的支持 如果代码希望执行二次幂的有符号整数除法,并且只在当前或未来的体系结构中运行,那么未来的编译器是否会将右移位运算符解释为执行其他操作?如果有现实的可能性,是否有好的方法来提供它而不影响可读性、性能或两者?是否有任何其他

许多人在讨论右移运算符时经常指出,C标准明确规定,负数右移的效果由实现定义。我可以理解这种说法的历史依据,因为C编译器已经被用于为各种不使用二补运算的平台生成代码。然而,据我所知,所有的新产品开发都是围绕着处理器展开的,这些处理器除了2的补码外,对任何类型的整数运算都没有内在的支持

如果代码希望执行二次幂的有符号整数除法,并且只在当前或未来的体系结构中运行,那么未来的编译器是否会将右移位运算符解释为执行其他操作?如果有现实的可能性,是否有好的方法来提供它而不影响可读性、性能或两者?是否有任何其他依赖项可以证明对操作员行为的完全假设是合理的(例如,代码在不支持函数X的实现上是无用的,如果不使用符号扩展右移,则实现不可能支持X)


注意:我在C99和C11标签下询问,因为我预计更新的语言功能将在其中,如果支持,将表明平台可能会使用右移,这在算术上相当于地板除法,并且对任何其他实现右移位的C99或C11编译器都很感兴趣。

< P>这只是其中的一个原因,但是请考虑信号处理的情况:

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个振幅的信号。这种不均匀性导致输出中存在直流偏置。出于这个原因,一些DSP处理器选择实现“从整数到0”的右移算法,或者其他方法。因为C99标准是按原样编写的,所以这些处理器仍然可以兼容

在这些处理器上,
-1>>1==0


理论上,现在编译器实现中存在一些微妙之处,这些细微之处可能会滥用所谓的“未定义行为”,超出后端cpu对寄存器(或“文件”或内存位置或其他位置)上实际整数的处理范围:

  • 交叉编译器是常见的东西:编译器在执行简单计算时可能会滥用依赖于实现的规范。考虑目标架构实现这一方式并托管另一种方式的情况。在您的特定示例中,编译时常量可能最终为1,即使目标体系结构中的任何程序集输出都会给出0(我想不出没有这样的体系结构)。然后再次,反之亦然。编译器实现者不需要关心(除了用户群抱怨之外)

  • 考虑一下生成中间抽象代码的CLANG和其他编译器。没有什么可以阻止类型机制在某些代码路径的中间时间优化某些操作直到最后一位(即,当它可以将代码减少为常量时,就会想到循环折叠),同时让程序集后端在运行时在其他路径中解决此问题。换句话说,你可以看到混合的行为。在这种抽象中,除了C语言所期望的标准之外,实现者没有义务遵守任何标准。假设所有整数数学都由任意精度的算术库完成,而不是直接映射到主机cpu整数。无论出于何种原因,实现都可能会决定这是未定义的,并将返回0。它可以用于任何有符号算术未定义的行为,ISO C标准中有很多这样的行为,特别是包装等

  • 考虑(理论上)这样一种情况,编译器没有发出完整的指令来执行低级操作,而是劫持了一个子操作。这方面的一个例子是带桶形移位器的ARM:显式指令(即add或其他指令)可能具有范围和语义,但子操作可能具有稍微不同的限制。编译器可以最大限度地利用这一点,因为行为可能会有所不同,例如,一种情况可以设置结果标志,而另一种情况不能。我想不出一个具体的例子来说明这一点,但有一种可能性,某些奇怪的指令只能处理“其他正常行为”的子集,编译器可能会认为这是一个很好的优化,因为未定义的行为实际上意味着未定义:-)

  • 除了运行时会有奇怪行为的奇怪体系结构之外,我能想到的一些原因就是为什么除了未定义的行为之外,你不能假设任何东西

    尽管如此,我们还必须考虑:

  • 您要求使用C99编译器。大多数奇怪的体系结构(即嵌入式目标)都没有C99编译器
  • 大多数“大规模”编译器实现者处理非常大的用户代码库,并且通常通过过度优化次要细节来支持噩梦。所以他们没有。或者他们像其他球员那样做
  • 在有符号整数“未定义行为”的特殊情况下,通常互补无符号操作是一个已定义的操作,即,我看到代码将有符号转换为无符号只是为了执行运算,然后将结果转换回
  • 我认为最好的是