gpt4 book ai didi

c - 按位运算导致意外的可变大小

转载 作者:行者123 更新时间:2023-12-03 07:29:22 24 4
gpt4 key购买 nike

语境

我们正在移植最初使用 8 位 C 编译器为 PIC 微 Controller 编译的 C 代码。用于防止无符号全局变量(例如,错误计数器)回滚回零的常用习惯用法如下:

if(~counter) counter++;

这里的按位运算符将所有位取反,并且该语句仅在 counter 时为真小于最大值。重要的是,无论大小如何,这都有效。

问题

我们现在的目标是使用 GCC 的 32 位 ARM 处理器。我们注意到相同的代码会产生不同的结果。据我们所知,按位补码操作返回的值与我们预期的大小不同。为了重现这一点,我们在 GCC 中编译:
uint8_t i = 0;
int sz;

sz = sizeof(i);
printf("Size of variable: %d\n", sz); // Size of variable: 1

sz = sizeof(~i);
printf("Size of result: %d\n", sz); // Size of result: 4

在第一行输出中,我们得到了我们所期望的: i是 1 个字节。但是, i 的按位补码实际上是 四个字节 这会导致问题,因为现在与此进行比较不会给出预期的结果。例如,如果执行(其中 i 是正确初始化的 uint8_t ):
if(~i) i++;

我们会看到 i “环绕”从 0xFF 回到 0x00。与以前的编译器和 8 位 PIC 微 Controller 的预期工作方式相比,GCC 中的这种行为有所不同。

我们知道我们可以通过像这样转换来解决这个问题:
if((uint8_t)~i) i++;

或者,通过
if(i < 0xFF) i++;

然而,在这两种变通方法中,变量的大小必须是已知的,并且对于软件开发人员来说很容易出错。这些类型的上限检查发生在整个代码库中。有多种大小的变量(例如, uint16_tunsigned char 等)并且在其他工作代码库中更改这些不是我们所期待的。

问题

我们对问题的理解是否正确,是否有可用的选项来解决这个问题,不需要重新访问我们使用过这个习语的每个案例?我们的假设是否正确,像按位补码这样的操作应该返回与操作数大小相同的结果?这似乎会中断,具体取决于处理器架构。我觉得我正在服用疯狂的药丸,而 C 应该比这更便携。同样,我们对此的理解可能是错误的。

从表面上看,这似乎不是一个大问题,但这个以前工作的习语已在数百个地方使用,我们渴望在进行代价高昂的更改之前了解这一点。

注意:这里有一个看似相似但不完全重复的问题: Bitwise operation on char gives 32 bit result

我没有看到那里讨论的问题的实际症结所在,即按位补码的结果大小与传递给运算符的结果大小不同。

最佳答案

你看到的是的结果整数促销 .在表达式中使用整数值的大多数情况下,如果值的类型小于 int该值被提升为 int .这在 C standard 的第 6.3.1.1p2 节中有所记录。 :

The following may be used in an expression wherever an intor unsigned int may be used

  • An object or expression with an integer type (other than intor unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
  • A bit-field of type _Bool, int ,signed int, orunsigned int`.

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.



因此,如果变量的类型为 uint8_t和值 255,在其上使用除强制转换或赋值以外的任何运算符将首先将其转换为类型 int在执行操作之前使用值 255。这就是为什么 sizeof(~i)给你 4 而不是 1。

第 6.5.3.3 节描述了整数提升适用于 ~运算符(operator):

The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E.



所以假设一个 32 位 int , 如果 counter具有 8 位值 0xff它被转换为 32 位值 0x000000ff , 并申请 ~给它给你 0xffffff00 .

处理这个问题的最简单的方法可能是在不知道类型的情况下检查递增后值是否为 0,如果是则递减它。
if (!++counter) counter--;

无符号整数的环绕适用于两个方向,因此将值递减为 0 会得到最大的正值。

关于c - 按位运算导致意外的可变大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61232081/

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