gpt4 book ai didi

c++ - 如何在固定宽度类型上强制执行无符号算术?

转载 作者:IT老高 更新时间:2023-10-28 22:39:42 25 4
gpt4 key购买 nike

以下(C99 和更高版本)代码想要计算一个正方形,限制为与原始固定宽度类型相同的位数。

    #include <stdint.h>
uint8_t sqr8( uint8_t x) { return x*x; }
uint16_t sqr16(uint16_t x) { return x*x; }
uint32_t sqr32(uint32_t x) { return x*x; }
uint64_t sqr64(uint64_t x) { return x*x; }

问题是:根据 int 大小,一些乘法可以在提升为 (signed) int 的参数上执行,结果溢出 (signed) int,因此就标准而言,结果未定义;并且可能是错误的结果,尤其是在(越来越少见的)不使用 two's complement 的机器上.

如果 int 是 32 位(分别为 16 位、64 位、80 或 128 位),则发生在 sqr16(分别为 sqr8, sqr32, sqr64) 当 x0xFFFFF (resp. 0xFF 0xFFFFFFFF0xFFFFFFFFFFFFFFFF)。这 4 个函数都不能在 C99 下正式移植!!

C11 或更高版本或某些版本的 C++ 是否可以解决这种不幸的情况?


一个简单有效的解决方案是:

    #include <stdint.h>
uint8_t sqr8( uint8_t x) { return 1u*x*x; }
uint16_t sqr16(uint16_t x) { return 1u*x*x; }
uint32_t sqr32(uint32_t x) { return 1u*x*x; }
uint64_t sqr64(uint64_t x) { return 1u*x*x; }

这是符合标准的,因为 1u 没有提升为 int 并且保持未签名;因此,左乘法,然后是右乘法,以无符号方式执行,因此定义良好,可以在必要数量的低位中产生正确的结果;最终隐式转换为结果宽度也是如此。

更新: 正如 comment by Marc Glisse 中的建议,我用八个编译器尝试了这个变体(三个版本的 GCC for x86 从 3.1 开始,MS C/C++ 19.00,Keil ARM 编译器 5,两个用于 ST7 变体的 Cosmic 编译器,Microchip MCC18)。它们都生成了与原始代码完全相同的代码(我在实际项目的 Release模式下使用了优化)。但是,编译器可能会生成比原始代码更差的代码。我还有其他几个嵌入式编译器可以尝试,包括一些 68K 和 PowerPC 的。

我们还有哪些其他选择,可以在可能更好的性能、可读性和简单性之间做出合理的平衡?

最佳答案

您在 <stdint.h> 中发现了整数类型别名的一个基本缺点。 :它们不包含有关类型转换等级的任何信息。因此,您无法控制这些类型的值是否进行整型提升,并且正如您正确观察的那样,当整型提升导致有符号类型时,表达式可能具有未定义的行为。

简而言之:您不能将别名类型用于执行模 2 的常用算术运算N。您需要使用其(已知!)转换等级至少为 int 的类型。 .

一般的解决方案是将您的操作数转换为unsigned int 的最小适当值。 , unsigned long intunsigned long long int (假设您的平台没有扩展的整数类型),然后评估表达式,然后转换回原始类型(具有正确的模块化行为)。在 C++ 中,您可能可以编写一个类型特征,以一种可移植的方式找出正确的类型。

作为一个更便宜的技巧,并且再次假设没有(更广泛的)扩展整数类型,您可以将所有内容提升为 unsigned long long int并希望您的编译器以一种有效的方式进行计算。

关于c++ - 如何在固定宽度类型上强制执行无符号算术?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40803059/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com